Forum: Ruby How can I get the arguments passed to the caller.

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.
5ca07e641fada5a88a09277c45bd7c1b?d=identicon&s=25 Stefan Kanev (Guest)
on 2009-01-25 20:21
(Received via mailing list)
Hey guys.

I have a rather weird question. I want to write a function that
programatically determines the arguments passed to its caller. Say, if i
do

$stuff = []

def bar(arg)
  foo
end

def foo
  first_arg = ....
  $stuff << first_arg
end

bar(42)

# By this point, $stuff would be [42]

I know it is quite the contrived question, but I'm not interested in
doing
something practical. Any leads?
9e2504e0b74e5384af09ce8a660afac4?d=identicon&s=25 Pascal J. Bourguignon (Guest)
on 2009-01-25 20:35
(Received via mailing list)
Stefan Kanev <stefan.kanev@gmail.com> writes:

>   foo
> end
>
> def foo
>   first_arg = ....
>   $stuff << first_arg
> end
>
> bar(42)

I don't think this is possible.


> # By this point, $stuff would be [42]
But to get this result you could write:

(def bar(*args)
   ($stuff = args)
 end)

(bar 42)

$stuff --> [42]
53581739a445ad78250a676dabddf55f?d=identicon&s=25 James Coglan (Guest)
on 2009-01-25 20:41
(Received via mailing list)
>  first_arg = ....
>  $stuff << first_arg
> end
>
> bar(42)
>
> # By this point, $stuff would be [42]



I think the closest you're going to get is for the calling function to
pass
its binding so that foo can read from it:

def bar(*args)
  foo(binding)
end
=> nil
def foo(env)
  puts env.eval("args.first")
end
=> nil
bar 'something'
something

I don't think you can do this transparently. You can't even refer to the
argument list within a single method (I'm thinking of the 'arguments'
object
in JavaScript) without mentioning the arguments by name.
5ca07e641fada5a88a09277c45bd7c1b?d=identicon&s=25 Stefan Kanev (Guest)
on 2009-01-25 21:32
(Received via mailing list)
So, suppose I want to get evil and go dig into frames and so on. I've
seen
ruby-debug do something close. Is there a part of the standard library
that
allows you to introspect that way (if so, I could not find it), or a gem
maybe? And if not and I'm bend on writing C code to achieve it, where
should
I start looking?
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2009-01-25 22:49
(Received via mailing list)
On Sun, Jan 25, 2009 at 9:30 PM, Stefan Kanev <stefan.kanev@gmail.com>
wrote:
> So, suppose I want to get evil and go dig into frames and so on. I've seen
> ruby-debug do something close. Is there a part of the standard library that
> allows you to introspect that way (if so, I could not find it), or a gem
> maybe? And if not and I'm bend on writing C code to achieve it, where should
> I start looking?
Depends, for methods with *args and optional arguments you have
definitely some heavy lifting to do. For all other methods however
it's easy:
   method( caller.first.sub(/.*in ./,"").sub(/.$/,"") ).arity
Probably not good enough?
cheers
Robert
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (candlerb)
on 2009-01-26 09:37
James Coglan wrote:
>>  first_arg = ....
>>  $stuff << first_arg
>> end
>>
>> bar(42)
>>
>> # By this point, $stuff would be [42]
>
>
>
> I think the closest you're going to get is for the calling function to
> pass
> its binding so that foo can read from it:

In which case, it might as well just pass its args instead :-)

There is the Binding.of_caller hack which you can find through a google
search.

Maybe you could combine this with Kernel#local_variables or
Binding#local_variables to do what you want? That's what debug.rb does

    when /^\s*l(?:ocal)?\s*$/
      var_list(eval("local_variables", binding), binding)

and just use eval to read them:

  def var_list(ary, binding)
    ary.sort!
    for v in ary
      stdout.printf "  %s => %s\n", v, eval(v, binding).inspect
    end
  end
5ca07e641fada5a88a09277c45bd7c1b?d=identicon&s=25 Stefan Kanev (Guest)
on 2009-01-27 15:32
(Received via mailing list)
Thanks for the advice. I would have never had thought of something as
straightforward as evaling 'local_variables' in the binding.
Unfortunatelly,
I believe that this doesn't yield the arguments if they are not named.

I'm actually trying, out of curiosity, to implement a very
straightforward
idea:

  %w{more chunky bacon}.each { puts it.length }

Like, have *it* to actually be the 'implicit blog argument', not unlike
perl's $_. Again, I'm doing that out of curiosity. Any ideas how I can
accomplish it without touching the interpreter's C code? :)
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2009-01-27 18:49
(Received via mailing list)
2009/1/27 Stefan Kanev <stefan.kanev@gmail.com>:
> perl's $_. Again, I'm doing that out of curiosity. Any ideas how I can
> accomplish it without touching the interpreter's C code? :)

IMHO you can't because the current value is only known by method
#each.  Wait, you could cook something up using thread local variables

18:41:58 tmp$ ./it.rb
4
6
5
18:42:41 tmp$ cat it.rb
#!/bin/env ruby

def it
  Thread.current[:each].last rescue nil
end

class Array
  alias _each each
  def each(&b)
    stack = Thread.current[:each] ||= []
    _each do |val|
      stack.push val
      begin
        b.call
      ensure
        stack.pop
      end
    end
  end
end

%w{more chunky bacon}.each { puts it.length }
18:42:42 tmp$

But note that you have to change *all* implementations of #each which
is difficult to achieve because classes can spring into existence all
the time. Alternatively write a global each which receives the
Enumerable as argument.

Cheers

robert
5ca07e641fada5a88a09277c45bd7c1b?d=identicon&s=25 Stefan Kanev (Guest)
on 2009-01-29 16:14
(Received via mailing list)
And I have to override Array#each. I'll also need to override #map,
#select
and so on. Not a good deal :(

On Tue, Jan 27, 2009 at 7:46 PM, Robert Klemme
This topic is locked and can not be replied to.