views:

37

answers:

1

I am generating some methods on the fly. The method body varies based on a certain criteria. I was relying on class_eval to generate conditional code.

%Q{
  def #{name}
   #{
   (name != "password") ? "attributes[:#{name}]" : 
                         "encrypt(attributes[:#{name}])"
   }
  end
}

Recently I have started using define_method. How do I generate conditional code blocks while using define_method?

Edit 1

Here are the possible approaches that I have considered:

1) Checking the name on during run time:

define_method(name) do       
 if name == password
   decrypt(attributes[name])     
 else
   attributes[name]
 end
end

This is not a preferred method as the check is done during run time.

2) Conditionally defining the entire method.

if (name == "password")
 define_method(name) do       
   decrypt(attributes[name])     
 end
else
 define_method(name) do       
   attributes[name]
 end
end

This approach has the disadvantage of having to repeat the code block just change a small part (as my actual method has several lines of code).

+2  A: 

I think because of closures you can do something like this:

  define_method name do
    if name=='password'
      decrypt(attributes[name])
    else
      attributes[name]
    end
  end

But the issue there is that the if will be evaluated on each call to the method. If you wanted to avoid that you'd need to pass different blocks to define_method for different behavior. e.g.

if name=='password'
  define_method(name) { decrypt(attributes[name]) }
else
  define_method(name) { attributes[name] }
end

alternately you could pass a lambda chosen by the if statement.

define_method(name, name=='password' ? lambda { decrypt(attributes[name]) } : lambda { attributes[name] }

One thing to think about, define_method can be slower than using eval.

BaroqueBobcat
+1, I have considered both approaches you have proposed. I have rejected the first approach for obvious reasons. Second approach is what I am doing now, but I have to repeat my code twice. Actual method I am adding has a bigger method body. so it is an eye-sore.
KandadaBoggu
I am curious about the last sentence, do you have any links that talks about this issue?
KandadaBoggu
After doing some searching about, it looks like it is a fair bit slower than using `def`, but eval isn't all that different. I didn't find any recent benchmarks though and something like this is very interpreter dependent.
BaroqueBobcat