1

I have the body of a ruby function as a string like

s = "x + 1"

I would like to do something like

fn = make_function(:x, s)
y = fn(10) # returns 11

What is the best way to achieve something like this?

Note that I'd rather not just keep eval'ing the string for each function call

1
  • The syntax you are looking for doesn't work with a function, it only works with a method. Commented Oct 14, 2012 at 3:13

3 Answers 3

2

This will eval the string once to define the function.

eval ['def fn(x)', s, 'end'].join("\n")

Here's something like your desired make_function

def make_function(klass, name, args, body)
  args = [ args ].flatten.map(&:to_s).join(', ')
  klass.class_eval ["def #{name} (#{args})", body, 'end'].join("\n")
end


irb> make_function(Object,:foo,[:x],'x*2')
=> nil
irb> foo(10)
=> 20
irb> foo(1.3)
=> 2.6
Sign up to request clarification or add additional context in comments.

Comments

0

eval a Proc!

def make_function(arguments, body)
    eval "Proc.new { |#{arguments}
              #{body}
          }"
end

f = make_function :x, 'x + 1'

puts f.call 10 # 11
puts f.call 21 # 22

1 Comment

This doesn't quite make a function in the way the OP asked. The syntax for calling a lambda is different than an ordinary method.
0

You really DO NOT WANT TO DO THIS. But it works as you wanted nevertheless.

module Kernel
  def make_function(*args, string)
    method_name = args.shift
    parameters = args


    args_string = parameters.map{|p| p.to_s}.join(",")

    instance_eval <<-RUBY 
      def #{method_name}(#{args_string})
        #{string}
      end 
    RUBY
  end
end

s = "x + 1"

make_function(:fn,:x,s)
puts fn(1) #=> 2

s2 = "x + y"
make_function(:foo,:x, :y,s2)
puts foo(1,5) #=> 2

Comments

Your Answer

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.