Archive for the ‘ruby’ Category

Dasherizing Builder::XmlMarkup in Rails

October 29, 2008 | rails, ruby, xml

Rails 2.x automatically dasherizes ActiveRecord inheritors when to_xml is called, but if you want to deal directly with Builder::XmlMarkup you have to go through some hoops to dasherize your element names. I solved this problem today with a simple subclass. Here's the code: [sourcecode language='ruby'] # Creates a Builder::Markup implementation that dasherizes all element and attribute names # Use this just like you would Builder::XmlMarkup class DasherizingBuilder < Builder::XmlMarkup def _start_tag(sym, attrs, end_too=false) super(sym.to_s.dasherize, attrs, end_too) end def _end_tag(sym) super(sym.to_s.dasherize) end def _insert_attributes(attrs, order=[]) return if attrs.nil? new_order= [] order.each {|item| new_order

Creating a Simple Private Gem Repository

October 8, 2008 | code, ruby

I recently wanted to create a simple local gem repository. Not all of the gems we write are relevant to the world at large, so github or rubyforge are not great solutions for hosting them. You can use the gem server command, but if you already have an apache HTTP server somewhere, incredibly easy to get a private gem repository going, server why not use that? 1. Copy the .gem file to your server scp your.gem your.server:/your/gem/path 2. Create a folder for hosting your gems on the server ssh user@your.server cd /var/www/html mkdir my_awesome_gems cd my_awesome_gems mkdir gems cp /your/gem/path/*.gem ./gems 3. Generate the gem index gem comes with a command generate_index which generates all of the files necessary for serving gems over HTTP. cd /var/www/html/my_awesome_gems gem generate_index At this point you should be able to access http://your.server/my_awesome_gems/ and see file listings. 4. Add your new source and install your gem on your client sudo gem sources -a http://your.server/my_awesome_gems/ You should be able to install your gems from this repository now! sudo gem install [your gem] That's it, you're now stashing gems in your own repo!

MonkeyPatching Class Methods in Ruby/Rails

April 29, 2008 | code, rails, ruby

I ran into this problem while trying to MonkeyPatch some class methods into existing Rails classes. Say you have the following Mooable module (as a rails plugin) that you want to dynamically inject into ActiveRecord::Base (or any ruby class for that matter). [sourcecode language='ruby'] # app/models/my_model.rb class MyModel < ActiveRecord::Base ... end # plugins/mooable/lib/mooable.rb module Mooable def moo return "Moo!" end end # plugins/mooable/init.irb ActiveRecord::Base.send :include, Mooable # test MyModel.new.moo # => "Moo!" [/sourcecode] But what if you wanted #moo to be a class method on ActiveRecord::Base? I was tempted to do the following: [sourcecode language='ruby'] #plugins/mooable/lib/mooable.rb module Mooable def self.moo return "Moo!" end end # test MyModel.moo # => NoMethodError: undefined method `moo' for MyModel:Class [/sourcecode] As you can see, simply defining the module method as a class method is a no-go (I'm sure this is a major nuby mistake, but it's always worth a try!) The best way I have found so far to monkeypatch new class methods into rails classes with a plugin is to use the Object#extend method inside of the module's self.included hook. The new class methods are defined within a sub-module Mooable::ClassMethods for easy inclusion. [sourcecode language='ruby'] # plugins/mooable/lib/mooable.rb module Mooable def self.included(klass) klass.extend ClassMethods end module ClassMethods def moo return "Moo Static/Class Method" end end def moo return "Moo Instance Method!" end end # test MyModel.moo # => "Moo Static/Class Method" MyModel.new.moo # => "Moo Instance Method!" [/sourcecode] This works like a charm.

Arriving at a DSL for XPath Testing in Rails

February 17, 2008 | code, rails, ruby, testing, xml

Recently I was writing custom Xml exporting for some of our Rails models. I favor TDD over just shoot-from-the-hip development, so I had to write some tests. For testing the validity of the XML, I chose XPath for its simplicity. As I added functionality (and thereby added tests) I noticed that my tests were becoming increasingly redundant, and that Test::Unit's syntax was making my test files ugly and more importantly hard to read. As I started DRY-ing up the individual tests and trying to find better ways to share code and make the tests more succinct, I noticed that I was driving very close to creating my own mini-DSL for testing Xml with Xpath. My Requirements for Xml Exporting A required element must always exist in the resulting Xml regardless of the model's state An optional element: Must exist when the model meets a certain state condition (i.e. the member is not null) Must not exist when that condition is not met A DSL That Meets My Testing Needs As mentioned earlier, this DSL evolved from repeated refactoring my tests in order to make them more clear. Here is an example of an XPath-based Xml test: [sourcecode lang='ruby'] xpath_tests_for @video_library do # ensure that the Xml always contains: #

XPath matching in Test::Unit

February 12, 2008 | code, rails, ruby, testing, xml

Inspired by an article on adding XPath matching to RSpec. I'm not using RSpec currently, and I also have a need for this functionality in my tests, so I decided to a helper for use in Test::Unit to achieve XPath matching in my tests. Add a new helper method: Add the following code to your test/test_helper.rb in order to create the assert_has_xpath method. [sourcecode lang='ruby'] #test/test_helper.rb require 'rexml/document' # Asserts that the specified xpath matches # at least once in the given document def assert_has_xpath (xpath, doc) doc = doc.is_a?(REXML::Document) ? doc : REXML::Document.new(doc) match = REXML::XPath.match doc, xpath assert !match.empty?, "Missing xpath '#{xpath}' in document: #{doc}" end [/sourcecode] Optionally, you can add the above to a module and include it in your test_helper, or in your individual tests. Use the helper in your tests: Now, in your tests, you can do something like the following [sourcecode lang='ruby'] #model.rb def to_xml options = {} xml = options[:builder] ||= Builder::XmlMarkup.new(options) xml.toys{ xml.toy "ball" xml.toy "iPhone" } end #model_test.rb def test_create_xml_creates_toys model = Model.new xml = model.to_xml assert_has_xpath "/toys[toy='iPhone']", xml end [/sourcecode] And voila! You now have XPath testing in your Test::Unit tests.