Generating Functions in Ruby

Hi!

I'm looking for a construction in Ruby to generate a (big) set of
functions. I need these functions to be class methods and called by
unique names since they are called via an external API.

As an example, let me create two functions that hard codes an addition
and then uses this in a small test program.

def FivePlusFour
  return 5+4
end

def OnePlusSeven
  return 1+7
end

puts("Five + Four is " + FivePlusFour().to_s)
puts("One + Seven is " + OnePlusSeven().to_s)

I would like a way to generate the methods in runtime. As an old C-
programmer, I'm looking for something like this:

# Define a macro
define SUM_TEMPLATE(namn,x,y) \\
def namn \\
  return x+y \\
end

# Create each function with a one-liner in runtime.
SUM_TEMPLATE(FivePlusFour, 5, 4)
SUM_TEMPLATE(OnePlusSeven, 1, 7)

# Test program
puts("Five + Four is " + FivePlusFour().to_s)
puts("One + Seven is " + OnePlusSeven().to_s)

Is this possible in Ruby?

(Please don't reply how to solve this silly example in a better way,
the true use case is of cause much more complex. But conceptually it's
the same.)

Best Regards,
Andreas Lundgren - Sweden

What you want is define_method. Ill gives you some links when I'm not on my
phone.

Hi!

I'm looking for a construction in Ruby to generate a (big) set of
functions. I need these functions to be class methods and called by
unique names since they are called via an external API.

As an example, let me create two functions that hard codes an addition
and then uses this in a small test program.

def FivePlusFour
return 5+4
end

def OnePlusSeven
return 1+7
end

puts("Five + Four is " + FivePlusFour().to_s)
puts("One + Seven is " + OnePlusSeven().to_s)

I would like a way to generate the methods in runtime. As an old C-
programmer, I'm looking for something like this:

# Define a macro
define SUM_TEMPLATE(namn,x,y) \\
def namn \\
return x+y \\
end

# Create each function with a one-liner in runtime.
SUM_TEMPLATE(FivePlusFour, 5, 4)
SUM_TEMPLATE(OnePlusSeven, 1, 7)

# Test program
puts("Five + Four is " + FivePlusFour().to_s)
puts("One + Seven is " + OnePlusSeven().to_s)

Is this possible in Ruby?

def SUM_TEMPLATE(name, x, y)
  class <<self;self;end.class_eval "def #{name}; #{x} + #{y}; end"
end

(Please don't reply how to solve this silly example in a better way,
the true use case is of cause much more complex. But conceptually it's
the same.)

Is it really? Do you always have one name and two values as input?
Can you give a bit more contextual information?

Cheers

robert

···

On Wed, May 18, 2011 at 3:46 PM, Andreas Lundgren <andreas.lundgren.x@gmail.com> wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

another way could be the method_missing method.
In my gem 'weekday' you can call methods like first_monday(yyyy,mm) ,
third_tuesday(...), last_sunday(...) and any other combination of a number
and weekday.

-Thomas

···

On 18 May 2011 15:46, Andreas Lundgren <andreas.lundgren.x@gmail.com> wrote:

I'm looking for a construction in Ruby to generate a (big) set of
functions. I need these functions to be class methods and called by
unique names since they are called via an external API.

--
Thomas Preymesser
thopre@gmail.com

Have a look at how ActionView (from Rails) caches its compiled
templates. It does this by defining methods on a module.

[actionpack/lib/action_view/template.rb]

      def compile(view, mod) #:nodoc:
...
        code = arity.abs == 1 ? @handler.call(self) :
@handler.call(self, view)

        source = <<-end_src
          def #{method_name}(local_assigns)
            _old_output_buffer = @output_buffer;#{locals_code};#{code}
          ensure
            @output_buffer = _old_output_buffer
          end
        end_src
...
        begin
          mod.module_eval(source, identifier, 0)
          ObjectSpace.define_finalizer(self, Finalizer[method_name,
mod])
        rescue Exception => e # errors from template code
          if logger = (view && view.logger)
            logger.debug "ERROR: compiling #{method_name} RAISED #{e}"
            logger.debug "Function body: #{source}"
            logger.debug "Backtrace: #{e.backtrace.join("\n")}"
          end

···

--
Posted via http://www.ruby-forum.com/.

1) Strings are mutable in ruby, so get rid of all those +'s.

2) Don't use back slashes in strings--unless you specifically intend to
use an escape character.

3)

My final dilemma is how to get the value of STUB_CALLS into
Templates.rb by defining it in my test program Impl.rb.

Why can't your methods have a 'debug' parameter with a default value?
Then for debugging, you can 'override' the default.

···

--
Posted via http://www.ruby-forum.com/\.

7) If you will have less than 9 parameters, you can do this:

param_str = temp = 'x1'

10.times do |i|
  temp = temp.succ
  param_str << ', ' << temp
end

p param_str

--output:--
"x1, x2, x3, x4, x5, x6, x7, x8, x9, y0, y1"

But in ruby, you can define variadic methods:

def my_meth(*args)
  args.each {|arg| p arg}
end

my_meth(1, 2, 3)
my_meth('a', 'b', 4)

--output:--
1
2
3
"a"
"b"
4

···

--
Posted via http://www.ruby-forum.com/.

10)

params = 'hello'
params = #{params};

--output:--
prog.rb:3: syntax error, unexpected $end

11) Here's some advice: buy a beginning ruby book and read it.

···

--
Posted via http://www.ruby-forum.com/.

Speaking of elegance, you can change this:

  class <<self;self;end.class_eval code

to this:

  instance_eval(code)

···

--
Posted via http://www.ruby-forum.com/.

Robert K. wrote in post #999483:

return 5+4
I would like a way to generate the methods in runtime. As an old C-
SUM_TEMPLATE(OnePlusSeven, 1, 7)

# Test program
puts("Five + Four is " + FivePlusFour().to_s)
puts("One + Seven is " + OnePlusSeven().to_s)

Is this possible in Ruby?

def SUM_TEMPLATE(name, x, y)
  class <<self;self;end.class_eval "def #{name}; #{x} + #{y}; end"
end

I need these functions to be class methods

...of what class? Perhaps something like this:

def SUM_TEMPLATE(the_class, meth_name, x, y)
  class_obj = Object.const_get(the_class)

  class_obj.singleton_class.class_eval do
    define_method(meth_name) do
      x + y
    end
  end
end

class Dog
end

SUM_TEMPLATE('Dog', 'FivePlusFour', 5, 4)
puts Dog.FivePlusFour

--output:--
9

···

On Wed, May 18, 2011 at 3:46 PM, Andreas Lundgren > <andreas.lundgren.x@gmail.com> wrote:

--
Posted via http://www.ruby-forum.com/\.

Robert K. wrote in post #999483:

def SUM_TEMPLATE(name, x, y)
  class <<self;self;end.class_eval "def #{name}; #{x} + #{y}; end"
end

I'm curious how you expected the op to use that method?

···

--
Posted via http://www.ruby-forum.com/\.

Hi!

This is why I did not put the real example at first, because then some
people that do not understand the code always brings these stupid
comments. I do not have any compilation errors, and the code works
perfectly, so I don't think that I need a beginning ruby book for that
reason. :slight_smile: (First params does not contain a simple string; please
note the escaped string characters in the code that generates params.
Kind of strings within strings).

I cannot change the function signature since I cannot change the upper
layer that makes calls to my Ruby glue layer... That is why I would
like to introduce debugging by making changes in the glue layer at
"compile" time. (In C I would have used a #define for the pre
processor.)

"1) Strings are mutable in ruby, so get rid of all those +'s." - I'm
not sure that I understand this but it sounds interesting, what does
it mean?

Thanks for input about creating loops, new language = new flavours,
and that is nice to adapt to! :slight_smile:

I think that I could make use of the variable parameter input, with
the extended error control code making sure all parameters are in
place, I think that this will be the same amount of code. But I
learned something new, so thanks!

BR,
Andreas

Robert K. wrote in post #999483:

def SUM_TEMPLATE(name, x, y)
   class<<self;self;end.class_eval "def #{name}; #{x} + #{y}; end"
end

I'm curious how you expected the op to use that method?

I am not sure I get your point. The method was intended to be used as a top level method similarly to how he formulated his C macro sample.

$ ruby19 <<CODE
> def SUM_TEMPLATE(name, x, y)
> class <<self;self;end.class_eval "def #{name}; #{x} + #{y}; end"
> end
> SUM_TEMPLATE("f",1,2)
> p f
> CODE
3

But, frankly, this use case seems to be so far away from his real use case that this approach is likely not what is needed. Since I have no further information I stick with the example and leave speculation about the nature of the real issue aside.

Kind regards

  robert

···

On 19.05.2011 03:55, 7stud -- wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

My bad to use the name "param" for two different content, but any
ways:

First params typically assembles to this:
x1.to_s + ', ' + x2.to_s + ', ' + x3.to_s + ', ' + x4.to_s
Now I have created the code, not the string.

The line
params_2 = #{params};
extends to:
params_2 = x1.to_s + ', ' + x2.to_s + ', ' + x3.to_s + ', ' + x4.to_s
and assembles my input so that
params_2 == 'myDB, 20110101, 20110201, all'

Output from the function when STUB_CALLS=1:
Calling shop_GetFundReq(x1, x2, x3, x4) with parameters <myDB,
20110101, 20110201, all>

BR,
Andreas

Andreas Lundgren wrote in post #1000535:

First params does not contain a simple string;
please note the escaped string characters in the code
that generates params. Kind of strings within strings

Yes, I noted that--see comment 6). What I failed to recognize was that
the line:

  params = #{params}

was part of a multiline string.

"1) Strings are mutable in ruby, so get rid of all those +'s." - I'm
not sure that I understand this but it sounds interesting, what does
it mean?

Every quoting mechanism creates a string and every + creates a new
combined string. So it's more efficient to use string interpolation:

i = 2
params = 'x1.to_s'
params = "#{params}, x#{i}.to_s"
p params

--output:--
"x1.to_s, x2.to_s"

In ruby not only can you push elements onto an array with the << method,
you can also push a string onto another string with the << method--which
alters the first string:

i = 2
params = 'x1.to_s'
params = "#{params}, x#{i}.to_s"

puts params
puts params.object_id

params << ', x3.to_s'

puts params
puts params.object_id

--output:--
x1.to_s, x2.to_s
77684510
x1.to_s, x2.to_s, x3.to_s
77684510

···

--
Posted via http://www.ruby-forum.com/\.

Robert K. wrote in post #999582:

I am not sure I get your point. The method was intended to be used as a
top level method similarly to how he formulated his C macro sample.

$ ruby19 <<CODE
> def SUM_TEMPLATE(name, x, y)
> class <<self;self;end.class_eval "def #{name}; #{x} + #{y}; end"
> end
> SUM_TEMPLATE("f",1,2)
> p f
> CODE
3

Oh, okay. But that isn't a class method.

···

--
Posted via http://www.ruby-forum.com/\.

Andreas Lundgren wrote in post #1000537:

The line
params_2 = #{params};
extends to:
params_2 = x1.to_s + ', ' + x2.to_s + ', ' + x3.to_s + ', ' + x4.to_s

Or you could do it like this:

params_2 = "#{x1}, #{x2}, #{x3}, #{x4}"

#{} interpolates the value of an expression into a string and calls to_s
automatically.

A slightly more DRY version:

params_2 = [x1, x2, x3, x4].join(", ")

Again, to_s is called automatically in this case.

Finally, if you used the *args syntax to collect a variable number of
args into an array, then it would become

params_2 = args.join(", ")

or even just: handle.call(['MethodNameIn','Params'],[method]+args)

Output from the function when STUB_CALLS=1:

Tiny suggestion: STUB_CALLS = false / true would be clearer, because
then you could say

do_something if STUB_CALLS

rather than

do_something if STUB_CALLS != 0

A global variable ($stub_calls) would arguably be preferable, since you
can change it at runtime without generating a warning. And better again
would be an instance variable of a class or module, because then it
lives in its own namespace.

module MyStuff
  @stub_calls = false # set the default
  def self.stub_calls
    @stub_calls
  end
  def self.stub_calls=(x)
    @stub_calls = x
  end
end

puts MyStuff.stub_calls
MyStuff.stub_calls = true
puts MyStuff.stub_calls

Another thing to look at is using heredoc, as it means you don't have to
worry about quoting double-quotes:

    class <<self;self;end.class_eval <<EOS
      def #{f_name}(#{arg_list})
        puts "Hello world"
      end
    EOS

Anyway, these are just tiny style suggestions. Having working code is
worth far more :slight_smile:

···

--
Posted via http://www.ruby-forum.com/\.

My bad to use the name "param" for two different content, but any
ways:

First params typically assembles to this:
x1.to_s + ', ' + x2.to_s + ', ' + x3.to_s + ', ' + x4.to_s

That does not look good. If you have to encode numbers in variable
names, you probably rather want to use an Array for that or even
generate that directly:

params = no_of_params.times.map {|i| "x#{i}"}.join(', ')

Now I have created the code, not the string.

The line
params_2 = #{params};
extends to:
params_2 = x1.to_s + ', ' + x2.to_s + ', ' + x3.to_s + ', ' + x4.to_s
and assembles my input so that
params_2 == 'myDB, 20110101, 20110201, all'

When looking at your posting from 2:55 you don't really need "params =
..." in the generated code.

Output from the function when STUB_CALLS=1:
Calling shop_GetFundReq(x1, x2, x3, x4) with parameters <myDB,
20110101, 20110201, all>

SUB_CALLS should be a boolean and treated as such.

I can see why 7stud wrote his recommendation: the code looks overly
complicated. Also, there are some issues, for example:

     handle.call(['MethodNameIn','Params'],[#{method},params]);

This only works if you call that method with something like

(..., "\"myMethod\"", ...)

where you should really passing the name plainly as string. Makes
usage much simpler and more robust. So in the method body you then
had

     handle.call(['MethodNameIn','Params'],['#{method}', params]);

Same reasoning applies in other locations such as return_format.

And if you get rid of the no_of_params you can simply use *args and do
not have to go through the hassle generating argument lists. If may
be though that you want to be able to query arity from the method and
have it fail fast if the argument list does not match in which case
it's OK to generate the argument list.

All in all it seems this is simpler and more redundancy free:

def GET_VALUE(f_name, method, return_format, no_of_params)
  args = no_of_params.times.map {|i| "x#{i}"}.join(", ")

  body = if STUB_CALLS
    %Q{printf("Calling #{method}(#{args}) with parameters <%p>\\n", [#{args}])}
  else
    %Q{
      oai = OA.instance
      handle = oai.getWIN32OLEHandle()
      handle.call(['MethodNameIn','Params'],['#{method}', [#{args}]]);
      ret_val = handle.GetControlValue(#{return_format});
      error = handle.GetControlValue('error out');
      return oai.checkForError(error) ? 'NaN': ret_val
    }
  end

  code = "def #{f_name}(#{args})\n#{body}\nend"
  puts code if ENV['DEBUG'] == 'true'
  class <<self;self;end.class_eval code
end

Cheers

robert

···

On Tue, May 24, 2011 at 9:25 AM, Andreas Lundgren <andreas.lundgren.x@gmail.com> wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

7stud -- wrote in post #1000754:

Andreas Lundgren wrote in post #1000535:

First params does not contain a simple string;
please note the escaped string characters in the code
that generates params. Kind of strings within strings

What I failed to recognize was that the line:

  params = #{params}

was part of a multiline string.

"1) Strings are mutable in ruby, so get rid of all those +'s." - I'm
not sure that I understand this but it sounds interesting, what does
it mean?

Every quoting mechanism creates a string and every + creates a new
combined string. So it's more efficient to use string interpolation:

i = 2
params = 'x1.to_s'
params = "#{params}, x#{i}.to_s"
p params

--output:--
"x1.to_s, x2.to_s"

In ruby not only can you push elements onto an array with the << method,
you can also use the << method to push a string onto another
string--which
alters the first string:

i = 2
params = 'x1.to_s'
params = "#{params}, x#{i}.to_s"

puts params
puts params.object_id

params << ', x3.to_s'

puts params
puts params.object_id

--output:--
x1.to_s, x2.to_s
77684510
x1.to_s, x2.to_s, x3.to_s
77684510

So your loop here:

    params = 'x1.to_s';
    for i in 2..no_of_params do
      arg_list = arg_list + ', x' + i.to_s;
      params = params + ' + \', \' + x' + i.to_s + '.to_s';
    end
    params = params+';';

would simplify to:

num_params = 4
params = 'x1.to_s'

2.upto(num_params).each do |i|
  params << ", x#{i}.to_s"
end

p params

--output:--
"x1.to_s, x2.to_s, x3.to_s, x4.to_s"

Also, compare that output to the output your loop produces:

  "x1.to_s + ', ' + x2.to_s + ', ' + x3.to_s + ', ' + x4.to_s"

You would get many errors using that string as an argument list for a
method.

···

--
Posted via http://www.ruby-forum.com/\.

That's true. But OP mentioned class methods in just one sentence but
all his examples (Ruby and C) were not using class methods. Besides
it should not be too difficult to modify the code to generate class
methods. I still would like to see more realistic requirements as all
speculations about proper ways to solve the problem are moot as long
as we do not know the problem.

Kind regards

robert

···

On Thu, May 19, 2011 at 8:00 PM, 7stud -- <bbxx789_05ss@yahoo.com> wrote:

Robert K. wrote in post #999582:

I am not sure I get your point. The method was intended to be used as a
top level method similarly to how he formulated his C macro sample.

$ ruby19 <<CODE
> def SUM_TEMPLATE(name, x, y)
> class <<self;self;end.class_eval "def #{name}; #{x} + #{y}; end"
> end
> SUM_TEMPLATE("f",1,2)
> p f
> CODE
3

Oh, okay. But that isn't a class method.

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/