Generating Functions in Ruby

Speaking of elegance, you can change this:

class <<self;self;end.class_eval code

to this:

instance_eval(code)

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(’, ')

your example generates code looks like this:
params = x1, x2, x3, x4
But with that I get an error (eval):3:in `+’: can’t convert Fixnum
into String (TypeError)

If it should work, I recon that it has to look like this:
params = “”#{" + no_of_params.times.map {|i| “x#{i}”}.join("}, #{")

  • “}”"

becaus I need the generated code to look like this:
params = “#{x1}, #{x2}, #{x3}, #{x4}”

handle.call([‘MethodNameIn’,‘Params’],[#{method},params]);
Yes, this was a bug…

params_2 = “#{x1}, #{x2}, #{x3}, #{x4}”
Yes, I could use this, but still I need to assembly this line since I
dont know the number of input parameters at coding time. And I know
that no input parameters contain any expressions that needs to be
evaluated since it is an input from my generated function.

Join and times.map was kind of cool, my prototype has now replaced the
first loops with this:
arg_list = no_of_params.times.map {|i| “x#{i}”}.join(", “)
args = no_of_params.times.map {|i| “x#{i}.to_s”}.join(”+’,’+")

(Using #{} instead of .to_s is basically the same:
args = “”#{" + no_of_params.times.map {|i| “x#{i}”}.join("}, #{") +
“}”"

BR,
Andreas

Andreas L. 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

–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.

I need this since parameters to win32ole are sent as a string with a
comma separated list of arguments. That is to send in x1=1, x2=‘A’ and
x3=1.5 I do the call:
handle.call([‘MethodNameIn’,‘Params’],[‘x1, x2, x3’, ‘1, A, 1.5’]);

The receiver mechanism does an “explode” on “,” and it’s then up to
the receiver to type cast the different elements to the expected types
(integer, character, float in this example)

BR,
Andreas

Andreas L. wrote in post #1000859:

–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.

I need this since parameters to win32ole are sent as a string with a
comma separated list of arguments. That is to send in x1=1, x2=‘A’ and
x3=1.5 I do the call:
handle.call([‘MethodNameIn’,‘Params’],[‘x1, x2, x3’, ‘1, A, 1.5’]);

If you need to send the string ‘x1, x2, x3’, then you need to create
that string, not this garbage:

“x1.to_s + ', ’ + x2.to_s + ', ’ + x3.to_s”

Do you not see the difference between these two strings:

“x1, x2, x3”
“x1.to_s + ', ’ + x2.to_s + ', ’ + x3.to_s”

Do you not see that those strings have different lengths? You seem to
think that ruby is going to do some type of eval on the second string
and you will end up with the first string, but ruby is not going to do
that. The second string above is a string, it is not an expression.
For instance, if you do this in C:

char str[] = “hello 2+2 world”;
printf("%s\n", str);

do you think the output is going to be:

hello 4 world

7stud – wrote in post #1000754:

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”

They are not the same. By the way, I think you have the terms
‘parameters’ and ‘arguments’ mixed up. Those aren’t parameters. Ah, I
see: you were tripping over your feet with all the internal quotes and
to_s’s and all you wanted was the string:

“x1, x2, x3, x4”

Hi!

This will be my last post in this thread, since now I’m back
explaining what was already described in the beginning.

Thanks all for your good answers.

If you just found this thread and are looking for answers about how to
generate functions in Ruby, the begining of this thread is very
informative.

How do you get from this function signature:

def GET_VALUE(f_name, method, return_format, no_of_params)
to this:
handle.call([‘MethodNameIn’,‘Params’],[‘x1, x2, x3’, ‘1, A, 1.5’]);

This is described earlier in this thread, see my post from Mon, 23 May
2011 05:56:34

Where do 1, ‘A’, and 1.5 come from?

Thas in example of input from the control layer that calls the
generated ruby glue function.

BR,
Andreas

Andreas L. wrote in post #1000859:

How do you get from this function signature:

def GET_VALUE(f_name, method, return_format, no_of_params)

to this:

handle.call([‘MethodNameIn’,‘Params’],[‘x1, x2, x3’, ‘1, A, 1.5’]);

Where do 1, ‘A’, and 1.5 come from?

Andreas L. wrote in post #1001483:

Hi!

This will be my last post in this thread, since now I’m back
explaining what was already described in the beginning.

Thanks all for your good answers.

I don’t like all the nested strings. It’s like the movie Inception:
dreams within dreams within dreams, which are hard to comprehend and
maintain. See if you like this better:

def GET_VALUE(f_name, method, return_format, no_of_params)
debug = (ARGV.shift == ‘debug’)

if debug
function = Proc.new {|*args|
puts “Calling #{f_name} with parameters: #{args}”
}
else
function = Proc.new {|*args|
#oai = OA.instance
#handle = oai.getWIN32OLEHandle()

  params = (1..no_of_params).map {|i| "x#{i}"}.join(', ')
  str_args = args.map {|arg| arg.to_s}.join(', ')
  p params
  p str_args

  #handle.call(['MethodNameIn','Params'],[params, str_args]);

  #ret_val = handle.GetControlValue(return_format);
  #error = handle.GetControlValue('error out');
  #return oai.checkForError(error) ? 'NaN': ret_val
}

end

singleton_class.class_eval do
define_method(f_name, &function)
end

end

GET_VALUE(‘shop_GetFundReq’, ‘getfundreq’, ‘ResultDbl’, 4)
sdb = 2
fr = shop_GetFundReq(sdb, 20110101, 20110201, ‘all’)

–output:–
“x1, x2, x3, x4”
“2, 20110101, 20110201, all”

Compare that output to the format you said you wanted.

handle.call([‘MethodNameIn’,‘Params’],[‘x1, x2, x3’, ‘1, A, 1.5’]);

You can uncomment all the commented out lines to get that method call.
Note that parameters are variables, and arguments are values, so I
followed that convention in my code.