B42cf6e7f67df424bf43e2c30a939079

The code is part of a library that parses .net msbuild project files containing property groups and is up at http://github.com/brunomlopes/ironbuildrake/ , together with tests.
Each property has a value that I want to access, and the value can be defined in function of other variables. A variable has the format $(varname).
This code is rather straightforward, but seems rather non-idiomatic.
The use of define_method in a class eval to avoid method_missing is a personal preference in order to avoid nasty recursive bugs and to allow for better runtime inspection of available methods.

class PropertyGroups
  def self.from_xml(xml)
    document = Document.new(xml)
    properties = Hash.new
    document.elements.each("Project/PropertyGroup/*") do |element|
      properties[element.name] = element.text.strip
    end
    return PropertyGroups.new(properties)
  end
 
  def initialize(elements)
    variable_regexp = /\$\([\w]+\)/
    elements.each_pair do |key, value|
      PropertyGroups.class_eval do
        define_method key.to_sym do ||
          replaced_value = value
          while variable_regexp.match(replaced_value)
            match = variable_regexp.match(replaced_value)
            full_var = match[0]
            var_name = full_var[2..-2]
            if elements.key? var_name
              replaced_value = replaced_value.sub(full_var, elements[var_name])
            else
              replaced_value = replaced_value.sub(full_var, "")
            end
          end
          return replaced_value
        end
      end
    end
  end
end

Refactorings

No refactoring yet !

D41d8cd98f00b204e9800998ecf8427e

kotrin

August 8, 2009, August 08, 2009 04:03, permalink

No rating. Login to rate!
class PropertyGroups
  def self.from_xml(xml)
    document = Document.new(xml)
    properties = {}
    document.elements.each("Project/PropertyGroup/*") do |element|
      properties[element.name] = element.text.strip
    end
    PropertyGroups.new(properties)
  end
  
  def initialize(elements)
    elements.each_pair { |k,v|
      meta_def(k.to_sym) {
        v.gsub(/\$\(([\w]+)\)/) { elements.key?($1) ? elements[$1] : "" }
      }
    }
  end
  
  def meta_def(m,&b)
    (class<<self;self end).send(:define_method,m,&b)
  end
end

Your refactoring





Format Copy from initial code

or Cancel