Forum: Ruby Dynamic method call

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
8fd4375f345fb3e46cc7c1b275bcfcea?d=identicon&s=25 Andrea Maschio (Guest)
on 2007-08-01 08:39
(Received via mailing list)
I'm trying, for the purpose of making something similar to a grammar, to
do
this

if_a_condition_is_true(condition, "method_name(arg1, arg2)")

where

def method_name(arg1, arg2)
#do something
end

i've tried many way to implement

def if_condition_is_true(condition , action)
#such as
eval(action)
#or
call self.method(action)

end

but noone worked, i've trying googling a bit but no chances. Have you
got an
idea on how to call dynamically a method, with his arguments?

Thanks a lot folks

--

Andrea Maschio

http://www.superandrew.it

A clever person solves a problem.
A wise person avoids it.

Einstein
9d1f5d2d9de70bd9a934f557dc95a406?d=identicon&s=25 Daniel ----- (liquid)
on 2007-08-01 08:46
(Received via mailing list)
On 8/1/07, Andrea Maschio <andrea.maschio@gmail.com> wrote:
> #do something
> end
>
> http://www.superandrew.it
>
> A clever person solves a problem.
> A wise person avoids it.
>
> Einstein



To call an arbitrary method on an object use send

object.send( :method_name_as_symbol [, arg1, arg2 ...] )

You can put that in an if statement etc or use

object.send( :method ) if some_condition_is_true

HTH
Daniel
D86ec78a7a258246684d15e09e51a170?d=identicon&s=25 Sharon Phillips (Guest)
on 2007-08-01 08:52
(Received via mailing list)
> end
>
> but noone worked, i've trying googling a bit but no chances. Have
> you got an
> idea on how to call dynamically a method, with his arguments?

Hi,
I'm not sure of why you need to implement it like this, but that's up
to you.
This works for me:

def if_condition_is_true(condition , action)
  eval(action) if condition
end

def method_name(arg1, arg2)
  puts arg1+ arg2
end

if_condition_is_true(true, "method_name(2, 3)")

Cheers,
Dave
8fd4375f345fb3e46cc7c1b275bcfcea?d=identicon&s=25 Andrea Maschio (Guest)
on 2007-08-01 09:41
(Received via mailing list)
Thank you very much guys, it worked. I was doing this for the purpose of
create a scripting language in my lang for testers to easy developing of
use
case testing with watir.
For english people is probably easier to read
31e038e4e9330f6c75ccfd1fca8010ee?d=identicon&s=25 Gregory Brown (Guest)
on 2007-08-01 16:32
(Received via mailing list)
On 8/1/07, Andrea Maschio <andrea.maschio@gmail.com> wrote:
> Thank you very much guys, it worked. I was doing this for the purpose of
> create a scripting language in my lang for testers to easy developing of use
> case testing with watir.
> For english people is probably easier to read

you really think that's easier to read than:

method_name(2,3) if condition

???
8fd4375f345fb3e46cc7c1b275bcfcea?d=identicon&s=25 Andrea Maschio (Guest)
on 2007-08-01 21:29
(Received via mailing list)
the problem is that method_name is a static call, i need to make it
dynamic
and choosed by the user/programmer, so at least he should type
eval("method_name(arg1,arg2)") if condition

but my aim was just to encapsulate this in a more comprehensible grammar
like

if_it_happens_that(is_true, "do_something(arg1,arg2)")

in another language that english it sound more different using english
word
"like if, then, end, do"

i know it could sound weird, but this was my need, and i solved it with
eval
(of course the internal logic is far more complex)



2007/8/1, Gregory Brown <gregory.t.brown@gmail.com>:
> method_name(2,3) if condition
>
> ???
>
>


--

Andrea Maschio

http://www.superandrew.it

A clever person solves a problem.
A wise person avoids it.

Einstein
31e038e4e9330f6c75ccfd1fca8010ee?d=identicon&s=25 Gregory Brown (Guest)
on 2007-08-01 21:38
(Received via mailing list)
On 8/1/07, Andrea Maschio <andrea.maschio@gmail.com> wrote:
> "like if, then, end, do"
>
> i know it could sound weird, but this was my need, and i solved it with eval
> (of course the internal logic is far more complex)

I still don't quite understand the problem you're tring to solve, but
consider using send(:method,arg1,arg2) instead of eval().  You're
begging for a mess using eval() to allow end users to input stuff.
E257c17034ca33ea3f75574f6b22e402?d=identicon&s=25 dohzya (Guest)
on 2007-08-01 21:49
(Received via mailing list)
Le jeudi 02 août 2007 à 04:27 +0900, Andrea Maschio a écrit :
> "like if, then, end, do"
>
> i know it could sound weird, but this was my need, and i solved it with eval
> (of course the internal logic is far more complex)

Do you want something like this  :
---
def sendif( args, &bloc )
  if args[:if]
    send args[:then].shift, *args[:then], &bloc
  else
    send args[:else].shift, *args[:else], &bloc if args[:else]
  end
end

sendif :if => 1 < 2, :then => [:p, "gagne"], :else => [:puts, "perdu"]
---
?
8fd4375f345fb3e46cc7c1b275bcfcea?d=identicon&s=25 Andrea Maschio (Guest)
on 2007-08-02 09:28
(Received via mailing list)
Ok, Gregory, now i understand that i didn't explain very well. The only
part
in wich the user (let's say a VERY junior programmer) is the scripting
interface i provide for him, so he will write
if_is_true(a_condition, "do_something(arg1,arg2)")

tha internal implementation is my matter, but if you think eval is bad
(i
probably understand why), the solution with

send(:method,arg1,arg2)

is probably good, but how can i allow a user to input the method name
with
his arguments? Anyway, i'm going to try.

2007/8/1, Gregory Brown <gregory.t.brown@gmail.com>:
> > if_it_happens_that(is_true, "do_something(arg1,arg2)")
> consider using send(:method,arg1,arg2) instead of eval().  You're
> begging for a mess using eval() to allow end users to input stuff.
>
>


--

Andrea Maschio

http://www.superandrew.it

A clever person solves a problem.
A wise person avoids it.

Einstein
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2007-08-02 14:55
(Received via mailing list)
On Aug 2, 2007, at 2:27 AM, Andrea Maschio wrote:

> send(:method,arg1,arg2)
>
> is probably good, but how can i allow a user to input the method
> name with
> his arguments? Anyway, i'm going to try.

Have you considered:

   if_is_true(condition) { do_something(...) }

?

That doesn't require eval() or send().

James Edward Gray II
13b511cd4fff9f72326e38526b9701fa?d=identicon&s=25 Todd Burch (toddburch)
on 2007-08-02 15:03
This may be slightly different, but I am calling a method dynamically
this way:

case tool
when "drill" then
   @operation = self.method(:drill) ;
when "cut"   then
   @operation = self.method(:cut) ;
when "bend"  then
   @operation = self.method(:bend) ;
end

@operation.call ;   # call whatever method was set.


Todd
C40020a47c6b625af6422b5b1302abaf?d=identicon&s=25 Stefano Crocco (crocco)
on 2007-08-02 15:12
(Received via mailing list)
Alle giovedì 2 agosto 2007, Todd Burch ha scritto:
> end
>
> @operation.call ;   # call whatever method was set.
>
>
> Todd

If the content of the tool variable are exactly the method names, then
you
don't need the case statement:

  @operation = self.method(tool)
  @operation.call

Stefano
F53b05cdbdf561cfe141f69b421244f3?d=identicon&s=25 unknown (Guest)
on 2007-08-02 15:17
(Received via mailing list)
Hi --

On Thu, 2 Aug 2007, Todd Burch wrote:

> end
>
> @operation.call ;   # call whatever method was set.

Unless I'm missing a subtlety, you could also do that as the somewhat
more concise:

   send(tool) if tool


David
13b511cd4fff9f72326e38526b9701fa?d=identicon&s=25 Todd Burch (toddburch)
on 2007-08-02 16:44
unknown wrote:
>
> Unless I'm missing a subtlety, you could also do that as the somewhat
> more concise:
>
>    send(tool) if tool
>
>
> David

Thanks for the shortcuts - I didn't know either of these techniques
could be done.  In my example, I do other things inside each WHEN
statement to set up the call, but I condensed my example to post.

Thanks!   Todd
B9b5ff40232c1dfd61238c2a90467f84?d=identicon&s=25 Wayne E. Seguin (Guest)
on 2007-08-02 18:35
(Received via mailing list)
On Aug 02, 2007, at 09:16 , dblack@rubypal.com wrote:
>   send(tool) if tool

I would (personally) take it a step farther:

send( tool ) if tool && respond_to? tool

or something similar.
31e038e4e9330f6c75ccfd1fca8010ee?d=identicon&s=25 Gregory Brown (Guest)
on 2007-08-02 18:47
(Received via mailing list)
On 8/2/07, James Edward Gray II <james@grayproductions.net> wrote:
> > probably understand why), the solution with
>
> ?
>
> That doesn't require eval() or send().

and

do_something(..) if condition

doesn't require anything.  I'm still missing what value this
if_is_true stuff is adding.
6087a044557d6b59ab52e7dd20f94da8?d=identicon&s=25 Peña, Botp (Guest)
on 2007-08-03 04:28
(Received via mailing list)
From: Gregory Brown [mailto:gregory.t.brown@gmail.com]
# do_something(..) if condition
#
# doesn't require anything.  I'm still missing what value this
# if_is_true stuff is adding.

i think he's asking for boolean obj so he can chain conditions.
soemthing like,

   cond.if_true(foo).bar.blah.if_true.baz.light

which is

   if cond
      if x = foo.bar.blah
         x.baz.light
      end
   end


kind regards -botp
31e038e4e9330f6c75ccfd1fca8010ee?d=identicon&s=25 Gregory Brown (Guest)
on 2007-08-03 05:21
(Received via mailing list)
On 8/2/07, Peña, Botp <botp@delmonte-phil.com> wrote:
> which is
>
>    if cond
>       if x = foo.bar.blah
>          x.baz.light
>       end
>    end

Sure, that could be helpful, but I'm not sure how you came up with
that based on what was asked.

For what you've shown there, I've often longed for a Null object

something like

class Null < BasicObject
  def self.method_missing(id,*args,&block)
     self
  end
end

module Kernel
  def if_true(condition)
     condition ? self : Null
  end
end

Note that I didn't even remotely test the above (though I have
implemented this before for fun), but that hopefully the idea is
preserved.
4d7bf65b4675b3e9575617929ab123f1?d=identicon&s=25 Paul Novak (Guest)
on 2007-08-03 16:01
(Received via mailing list)
> On 8/1/07, Andrea Maschio <andrea.masc...@gmail.com> wrote:
>
> > Thank you very much guys, it worked. I was doing this for the purpose of
> > create a scripting language in my lang for testers to easy developing of use
> > case testing with watir.
> > For english people is probably easier to read.

Andrea,

Hmm.  A 'scripting language for testers' sounds like the RSpec
DSL[0].  Your cases should map to RSpec contexts very nicely.

Regards,

Paul.

[0] http://rspec.rubyforge.org/index.html
F53b05cdbdf561cfe141f69b421244f3?d=identicon&s=25 unknown (Guest)
on 2007-08-03 16:55
(Received via mailing list)
Hi --

On Wed, 1 Aug 2007, Andrea Maschio wrote:

> Thank you very much guys, it worked. I was doing this for the purpose of
> create a scripting language in my lang for testers to easy developing of use
> case testing with watir.
> For english people is probably easier to read

Maybe, maybe not....   I would tend to say:

   if 5 is greater than 3

rather than

   if this condition is true: 5 is greater than 3

But of course it depends on the wider context you're developing.


David
5d38ab152e1e3e219512a9859fcd93af?d=identicon&s=25 David Chelimsky (Guest)
on 2007-08-03 20:19
(Received via mailing list)
On 8/3/07, Paul Novak <novakps@gmail.com> wrote:
> DSL[0].  Your cases should map to RSpec contexts very nicely.
Actually, we already have integration with Watir built into spec/ui
(available from http://rubyforge.org/frs/?group_id=797). Admittedly it
is less mature than rspec as a whole, but I use it all the time to
drive in-browser testing.

Also, we're in the process of merging rbehave's story runner into
rspec to make rspec a full-stack bdd framework. It won't be long
before we're able to integrate that w/ spec/ui as well, in which case
you'll be able to write in-browser tests that look like this:

Scenario "anonymous user tries to access private page" do
  Given "an anonymous user" { ... }
  When "go to /private/page" { ... }
  Then "should redirect to /login" { ... }
end

Sadly, that's a few months off. Happily, that's JUST a few months off !
8fd4375f345fb3e46cc7c1b275bcfcea?d=identicon&s=25 Andrea Maschio (Guest)
on 2007-08-04 00:13
(Received via mailing list)
Thanks a lot, Paul, I'll take a look for sure

2007/8/3, Paul Novak <novakps@gmail.com>:
> Andrea,
>
>
>


--

Andrea Maschio

http://www.superandrew.it

A clever person solves a problem.
A wise person avoids it.

Einstein
8fd4375f345fb3e46cc7c1b275bcfcea?d=identicon&s=25 Andrea Maschio (Guest)
on 2007-08-04 00:25
(Received via mailing list)
Yes, probably i started this post not imaging it would be difficult to
imagine a syntax mixed and merged from 2 language, but since most of you
people aren't speaking english as a first language, i think it would be
easy
to imagine that for a tester(not a developer, but someone who will use
my
'scripting language' built wrapping watir facilities) would be nicer and
easier to understand something like

se_presente_testo("inserimento effettuato", "registra('testUseCase123',
'completo'))

than

if  presente_testo then blabla

or blabla if presente _testo

That was not he point, which was how to implement a dynamic call to a
method. The grammar stuff probably at beginning was just a subtilety,
but it
slighty began to make  me understand some underlying language mechanisms
that  i believe are as powerful as easier compared to other language's
features.

So thanks a lot for the time to discuss about this, i really like this
list
and i find it is truly live and active as a Ruby community should be! :)

2007/8/3, dblack@rubypal.com <dblack@rubypal.com>:
>
>
> David
>
> --
> * Books:
>    RAILS ROUTING (new! http://www.awprofessional.com/title/0321509242)
>    RUBY FOR RAILS (http://www.manning.com/black)
> * Ruby/Rails training
>      & consulting:  Ruby Power and Light, LLC (http://www.rubypal.com)
>
>


--

Andrea Maschio

http://www.superandrew.it

A clever person solves a problem.
A wise person avoids it.

Einstein
31e038e4e9330f6c75ccfd1fca8010ee?d=identicon&s=25 Gregory Brown (Guest)
on 2007-08-04 16:39
(Received via mailing list)
On 8/3/07, Andrea Maschio <andrea.maschio@gmail.com> wrote:
> Yes, probably i started this post not imaging it would be difficult to
> imagine a syntax mixed and merged from 2 language, but since most of you
> people aren't speaking english as a first language, i think it would be easy
> to imagine that for a tester(not a developer, but someone who will use my
> 'scripting language' built wrapping watir facilities) would be nicer and
> easier to understand something like
>
> se_presente_testo("inserimento effettuato", "registra('testUseCase123',

What still bugs me is that you are using a dynamic call where there is
no need.

It's entirely possible to write a method that allows you to do something
like:

se_presenete_testo("inserimento effettuato") { registra 'testUseCase123'
}

which would be one less language construct to reinvent.
F690ec04b0501b74b033fc64ff4f682b?d=identicon&s=25 Dean Wampler (Guest)
on 2007-08-04 17:01
(Received via mailing list)
On 8/2/07, Todd Burch <promos@burchwoodusa.com> wrote:
>
> Thanks for the shortcuts - I didn't know either of these techniques
> could be done.  In my example, I do other things inside each WHEN
> statement to set up the call, but I condensed my example to post.
>
> Thanks!   Todd


You could still get the same benefit by setting up a hash of name-value
papers, e.g.,

actions = {
  "drill" => :do_the_drill_thang,
  "cut"  => :slice_and_dice,
  ...
}

send(actions[tool]) if tool

An alternative, maybe better, idea would be to define method aliases,
e.g.,

method_alias :drill, :do_the_drill_thang
...

send(tool) if tool

dean
Fc12729d592e6d8cd98eaa8e0eec4240?d=identicon&s=25 Bas van Gils (Guest)
on 2007-08-04 21:03
(Received via mailing list)
On Thu, Aug 02, 2007 at 04:48:30AM +0900, dohzya wrote:
>
> sendif :if => 1 < 2, :then => [:p, "gagne"], :else => [:puts, "perdu"]
> ---
> ?

Damn, that's elegant!

  Bas

--
Bas van Gils <bas@van-gils.org>, http://www.van-gils.org
[[[ Thank you for not distributing my E-mail address ]]]

Quod est inferius est sicut quod est superius, et quod est superius est
sicut
quod est inferius, ad perpetranda miracula rei unius.
31e038e4e9330f6c75ccfd1fca8010ee?d=identicon&s=25 Gregory Brown (Guest)
on 2007-08-06 01:47
(Received via mailing list)
On 8/4/07, Bas van Gils <bas@van-gils.org> wrote:
> > end
> >
> > sendif :if => 1 < 2, :then => [:p, "gagne"], :else => [:puts, "perdu"]
> > ---
> > ?
>
> Damn, that's elegant!

I dig it too, though I like better:

sendif 1 < 2, :then => [:p, "gagne"],  :else => [:puts, "perdue"]

just because it kills the redundant if.
49d779534da06c3718084bce68f53e66?d=identicon&s=25 evanwebb@gmail.com (Guest)
on 2007-08-06 02:10
(Received via mailing list)
On Aug 5, 4:47 pm, "Gregory Brown" <gregory.t.br...@gmail.com> wrote:
> > >     send args[:then].shift, *args[:then], &bloc
>
> I dig it too, though I like better:
>
> sendif 1 < 2, :then => [:p, "gagne"],  :else => [:puts, "perdue"]
>
> just because it kills the redundant if.

To put in my 2 cents, this offends my senses. Whats wrong with:

if 1 < 2
 p "gagme"
else
 puts "perdue"
end

or even
1 < 2 ? p "gagme" : puts "perdue"

Calling a method with a hash argument just to perform a condition
makes me cringe, performance wise. Plus it just seems so overly
clever.
31e038e4e9330f6c75ccfd1fca8010ee?d=identicon&s=25 Gregory Brown (Guest)
on 2007-08-06 02:54
(Received via mailing list)
On 8/5/07, evanwebb@gmail.com <evanwebb@gmail.com> wrote:
> > > >   if args[:if]
> > > Damn, that's elegant!
>  p "gagme"
> else
>  puts "perdue"
> end
>
> or even
> 1 < 2 ? p "gagme" : puts "perdue"
>
> Calling a method with a hash argument just to perform a condition
> makes me cringe, performance wise. Plus it just seems so overly
> clever.

Full ack, though if you look through some of the mess we have seen in
this thread, this looks good by comparison.  The issue is that the OP
is building a DSL for non-english speakers and needs to have an if
construct that matches the language.  So the send_if bit is part of
the implementation details for that.

That having been said, the only benefit of the above is that it lends
nicely to dynamic buildup of calls, but I'd prefer passing around
lambdas, all else considered equal.  It just seems like the OP wants
to avoid blocks in general.
E257c17034ca33ea3f75574f6b22e402?d=identicon&s=25 dohzya (Guest)
on 2007-08-06 12:33
(Received via mailing list)
Le lundi 06 août 2007 à 08:47 +0900, Gregory Brown a écrit :
> > >   end
> sendif 1 < 2, :then => [:p, "gagne"],  :else => [:puts, "perdue"]
>
> just because it kills the redundant if.
>

in ruby 1.9 :
---
sendif 1 < 2, then: [:p, "gagne"], else: [:puts, "perdue"]
---
as elegant as Objective-C !


if I am very evil :
---
def then &b ; Proc.new &b ; end
def else &b ; Proc.new &b ; end
def sendif test, then, else
  test ? then.call : else.call
end
sendif 1 < 2, then {p "gagne"}, else {puts "perdue"}
---
but it's too expensive for a simple function...
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2007-08-06 12:45
(Received via mailing list)
On 8/6/07, dohzya <dohzya@gmail.com> wrote:
> > > >     send args[:else].shift, *args[:else], &bloc if args[:else]
> >
>
> but it's too expensive for a simple function...
let us make it cheaper then

def then &b; b.call end
def else &b;  b.call end
sendif 1 < 2, then { p "gagnee"}, else { puts "perdu"}

My wife made me change the output ;)

Cheers
Robert
E257c17034ca33ea3f75574f6b22e402?d=identicon&s=25 dohzya (Guest)
on 2007-08-07 01:42
(Received via mailing list)
Le lundi 06 août 2007 à 19:44 +0900, Robert Dober a écrit :
> def then &b; b.call end
> def else &b;  b.call end
> sendif 1 < 2, then { p "gagnee"}, else { puts "perdu"}
output: "gagneeperdu" (or "perdugagnee")
result: nil

the 2 arguments are valued BEFORE calling the function...
you can't do that without macro or lazy-function
This topic is locked and can not be replied to.