[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

How can I get the arguments passed to the caller.

Aquarius

1/25/2009 7:18:00 PM

[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?

8 Answers

pjb

1/25/2009 7:31:00 PM

0

Stefan Kanev <stefan.kanev@gmail.com> 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__

James Coglan

1/25/2009 7:39:00 PM

0

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

Aquarius

1/25/2009 8:30:00 PM

0

[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 <jcoglan@googlemail.com>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.
>

Robert Dober

1/25/2009 9:46:00 PM

0

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

Brian Candler

1/26/2009 8:36:00 AM

0

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
--
Posted via http://www.ruby-....

Aquarius

1/27/2009 2:30:00 PM

0

[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 <b.candler@pobox.com> 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(?: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
> --
> Posted via http://www.ruby-....
>
>

Robert Klemme

1/27/2009 5:46:00 PM

0

2009/1/27 Stefan Kanev <stefan.kanev@gmail.com>:
> 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

Aquarius

1/29/2009 3:11:00 PM

0

[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
<shortcutter@googlemail.com>wrote:

> 2009/1/27 Stefan Kanev <stefan.kanev@gmail.com>:
> > 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
>
>