1

I'm trying to find a way to evaluate an expression that consists of a function and argument. The problem is, I don't want the argument converted into a string.

Specifically, I have the function x="display_datetime" of type String, which takes an object y of type Time. The function name is created dynamically, so I can't just type, display_datetime(y).

What I've tried:

  • eval("#{x}(#{y})") - This is how I'd normally do it, but this converts the Time to a string. The whole purpose of "display_datetime" is to do a custom Time to string conversion, so this would not be useful

  • x.send(y) - This does not compile, because send is meant to send classes functions, not functions arguments.

  • x.constantize... - also doesn't compile, even if x includes the classname.

  • y.send(:to_s(:datetime)) This approach is less than ideal, but I still can't get it to work. display_datetime just calls y.to_s(:datetime), so I tried setting the dynamically generated function name x to simply be .to_s(:datetime), then invoking x on y with the send command. This would work, except for the fact that to_s takes an argument. I don't know how to call send (or try) when the argument being sent has to take an argument
  • Another idea I've had is to override the Time class to add a conversion function to it like to_s, but that doesn't take any argument.

Those last two approaches are less than ideal. I feel like there has to be some better way of doing this along the lines of the first 3 approaches.

Any feedback is appreciated.

Thanks

asked Jul 19, 2013 at 7:38
3
  • 1
    under which namespace did you create your display_datetime Commented Jul 19, 2013 at 7:43
  • Under ApplicationHelper Commented Feb 10, 2014 at 19:46
  • Sorry for not responding to posts. This somehow fell off the radar. I will respond now. Commented Feb 10, 2014 at 19:48

2 Answers 2

3

There is no problem with send. Do this:

send(x, y)
answered Jul 19, 2013 at 7:41
1
  • This works. You just need to call send on the object. So I'm accepting this answer. I didn't know send could take a function name and an argument list. I verified that if y is of type fixnum, the type is still fix num inside the function. So there's no string conversion taking place. This makes this the best approach for my needs. Commented Feb 10, 2014 at 19:52
2

Given

s = "display_datetime" # function name, dynamic
y = Time.now # or some other Time object

And some object o that responds to the display_datetime() method, you can call o.display_datetime dynamically in several ways, at least:

o.send(s.intern, y) # => o.send(:display_datetime, y)

Or,

eval("o.#{s}(y)") # => eval("o.display_datetime(y)")

Alternatively,

o.instance_eval("#{s}(y)") # => o.instance_eval("display_datetime(y)")

Or if you want evalception, if the variable n contains the name of the variable o:

n = 'o'
eval %Q(#{n}.send(:instance_eval, "\#{s}(y)"))
answered Jul 19, 2013 at 10:05
1
  • Thanks for your answer. Your first solution works well for me. The last 3 don't work, because y gets stringified in all those. I gave the answer to the other guy though, because his came in earlier. Commented Feb 10, 2014 at 19:57

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.