How can I get the arguments passed to the caller.

Discussion in 'Ruby' started by Stefan Kanev, Jan 25, 2009.

  1. Stefan Kanev

    Stefan Kanev Guest

    [Note: parts of this message were removed to make it a legal post.]

    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?
    Stefan Kanev, Jan 25, 2009
    #1
    1. Advertising

  2. Stefan Kanev <> writes:

    > [Note: parts of this message were removed to make it a legal post.]
    >
    > 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)


    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]

    > I know it is quite the contrived question, but I'm not interested in doing
    > something practical. Any leads?



    --
    __Pascal Bourguignon__
    Pascal J. Bourguignon, Jan 25, 2009
    #2
    1. Advertising

  3. Stefan Kanev

    James Coglan Guest

    [Note: parts of this message were removed to make it a legal post.]

    > 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 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.
    James Coglan, Jan 25, 2009
    #3
  4. Stefan Kanev

    Stefan Kanev Guest

    [Note: parts of this message were removed to make it a legal post.]

    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?

    On Sun, Jan 25, 2009 at 9:39 PM, James Coglan <>wrote:

    > > 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 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.
    >
    Stefan Kanev, Jan 25, 2009
    #4
  5. Stefan Kanev

    Robert Dober Guest

    On Sun, Jan 25, 2009 at 9:30 PM, Stefan Kanev <> 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
    Robert Dober, Jan 25, 2009
    #5
  6. 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(?:eek:cal)?\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
    --
    Posted via http://www.ruby-forum.com/.
    Brian Candler, Jan 26, 2009
    #6
  7. Stefan Kanev

    Stefan Kanev Guest

    [Note: parts of this message were removed to make it a legal post.]

    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? :)

    On Mon, Jan 26, 2009 at 10:35 AM, Brian Candler <> wrote:

    > 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(?:eek:cal)?\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
    > --
    > Posted via http://www.ruby-forum.com/.
    >
    >
    Stefan Kanev, Jan 27, 2009
    #7
  8. 2009/1/27 Stefan Kanev <>:
    > 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? :)


    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

    --
    remember.guy do |as, often| as.you_can - without end
    Robert Klemme, Jan 27, 2009
    #8
  9. Stefan Kanev

    Stefan Kanev Guest

    [Note: parts of this message were removed to make it a legal post.]

    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
    <>wrote:

    > 2009/1/27 Stefan Kanev <>:
    > > 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? :)

    >
    > 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
    >
    > --
    > remember.guy do |as, often| as.you_can - without end
    >
    >
    Stefan Kanev, Jan 29, 2009
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. dee
    Replies:
    9
    Views:
    504
    Joseph Byrns
    Apr 15, 2005
  2. Anand
    Replies:
    2
    Views:
    897
    Anand
    Sep 11, 2003
  3. Adam Wozniak
    Replies:
    40
    Views:
    948
    Martin Demberger
    Aug 17, 2009
  4. Mark
    Replies:
    2
    Views:
    390
  5. Csaba  Gabor
    Replies:
    9
    Views:
    141
Loading...

Share This Page