Question

I have written the following code in my Rails app to generate XML. I am using Aptana IDE to do Rails development and the IDE shows a warning that the code structure is identical in both the blocks. What changes can be done to the code to remove the duplicity in structure? Is there any other way to write the same?

xml.roles do
    @rolesList.each do |r|
        xml.role(:id => r["role_id"], :name => r["role_name"])
    end
end

xml.levels do
    @levelsList.each do |lvl|
        xml.level(:id => lvl["level_id"], :name => lvl["level_name"])
    end
end
Was it helpful?

Solution

I had the same issue with using the send method and getting tags that looked like <send:id>12</send:id>. To resolve, I used the "tag!" method. So I think your code would look like:

def build_xml(node_name, node_list)
  xml.tag!(node_name.pluralize) do
    node_list.each do |node|
      id_str = node["#{node_name}_id"]
      name_str = node["#{node_name}_name"]
      xml.tag!(node_name, :id => id_str, :name => name_str)
    end
  end
end

OTHER TIPS

I had a similar idea to @nathandva, but using send properly:

def list_to_xml(node_name, list)
  xml.send(node_name.pluralize.to_sym) do 
    list.each do |item|
      xml.send(node_name.to_sym, :id => r["#{node_name}_id"], 
               :name => r["#{node_name}_name"])
    end
  end
end

Since it adds visual complexity, this change may not be the best. The biggest question is: if you are likely to make a change to xml.roles structure, are you likely to change xml.levels as well? If so, definitely remove the duplication. It is also important to name the method something that will make sense to you upon reading it; add that point the complexity will be reduced not increased.

Something like this?

def build_xml(node_name, node_list)
  xml.send(node_name.pluralize) do
    node_list.each do |node|
      id_str = node["#{node_name}_id"]
      name_str = node["#{node_name}_name"]
      xml.send(node_name, :id => id_str, :name => name_str)
    end
  end
end

build_xml("role", @roleslist)
build_xml("level", @levelslist)

I am trying to use send instead of eval [which i did not do to well: edited it to correct it --thanks to Kathy Van Stone].

Edit 26/12 because the xml builder will capture the send and use it as a xml branch there are two possible options, use the send method instead, like this

      xml.__send__(node_name, :id => id_str, :name => name_str)

but i am not sure whether it will create a <__send__:roles> instead. You could always fall back to

      eval("xml.#{node_name} :id => '#{id_str}', :name => '#{name_str}'")

which should definitely work (but eval should always be used a last resort).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top