accessing the currently running method

Discussion in 'Ruby' started by Kev Jackson, Mar 30, 2006.

  1. Kev Jackson

    Kev Jackson Guest

    is caller the best way to access the name of the current method?

    ie if I have a method called x, is there any other way to determine at
    runtime the exact method that is executing? caller would return an
    array (limited by the int param) of the call stack, but I'd still have
    to search across the array (with a regexp) to extract the method name

    with caller I can do something like...

    ms = ["prog:1:in `x'"]

    ms.each { |m| /x/=~m do_stuff }

    Is there no other way? no Kernel.running_method, no Kernel.executing?
    Are there any libraries that would give me this level of inspection
    without extending Kernel? (I'm thinking of evil.rb here)

    No biggy, just interested if anyone else has ever wanted/needed to get
    this info in a running program, and what they did to do it

    Kev
     
    Kev Jackson, Mar 30, 2006
    #1
    1. Advertising

  2. Kev Jackson wrote:
    > is caller the best way to access the name of the current method?
    >
    > ie if I have a method called x, is there any other way to determine at
    > runtime the exact method that is executing? caller would return an
    > array (limited by the int param) of the call stack, but I'd still have
    > to search across the array (with a regexp) to extract the method name
    >
    > with caller I can do something like...
    >
    > ms = ["prog:1:in `x'"]
    >
    > ms.each { |m| /x/=~m do_stuff }
    >
    > Is there no other way? no Kernel.running_method, no Kernel.executing?
    > Are there any libraries that would give me this level of inspection
    > without extending Kernel? (I'm thinking of evil.rb here)


    There is binding_of_caller which might or might not help you - depending
    on what you want to do.

    Another option is to use set_trace_func to set up something that keeps
    track of method invocations.

    > No biggy, just interested if anyone else has ever wanted/needed to get
    > this info in a running program, and what they did to do it


    Certainly, from time to time. What do *you* need it for?

    Kind regards

    robert
     
    Robert Klemme, Mar 30, 2006
    #2
    1. Advertising

  3. Kev Jackson

    Kev Jackson Guest


    >
    > There is binding_of_caller which might or might not help you -
    > depending on what you want to do.
    >

    I'll look into it thanks

    > Another option is to use set_trace_func to set up something that keeps
    > track of method invocations.
    >
    >> No biggy, just interested if anyone else has ever wanted/needed to
    >> get this info in a running program, and what they did to do it

    >
    >
    > Certainly, from time to time. What do *you* need it for?


    I currently have a yaml file

    pg_401:
    corp_nm_kn: 'JP text...' <= corprate name (kana)
    etc

    and a ruby script that uses watir to execute a set of web app page
    transitions whilst filling in the data read from the yaml file.

    in standard watir
    ie.text_field:)id, 'some id value for text field').set(v)

    as I'm reading the data from a yaml file I get a hash of hashes (ok I
    could get an object or anything else, but at the moment I get back a
    hash of hashes)

    so my calls to watir look like

    ie.text_field:)id,
    test_data['pg_401']['corp_name_field']).set(test_data['pg_401']['corp_name']

    I've managed to reduce this to

    text :id, :pg_401, :corp_name which is expanded to the correct call
    using method_missing, I'd like to reduce this further to

    text :corp_name

    I can remove the :pg_401 by knowing the currently executing method, I
    can remove the :id by simply trying all options :id, :name, :matches (I
    think) and rescuing the Exception raised.

    Ultimately, I'd rather have all these field_type, :field_name pairs
    defined in yaml and then create a script on the fly and execute it. At
    the moment, the qc team will have to edit two files (data in yaml
    format, and script in ruby).

    Why would I want to reduce the amount of text typed by the qc team (who
    will be writing these scripts)?:

    1 - because it's possible to reduce the workload
    2 - because some of the screens (pg_XXX) have more than 400 fields that
    must be entered (not my fault, I had no hand in designing the UI, for
    that you can blaim HP japan)
    3 - because I'm starting to get why people think that DSLs and lisp
    macros are a good thing (I think I reached the tipping point of
    understanding, when I saw loads of my first calls to the watir library
    and thought, "That's irritatingly repetitive, surely the computer can do
    that kind of work for me").

    Currently I have

    caller[0][/in: `.+(pg_\d{3})/,1]
    which adequately returns the current method (given the current
    convention of naming the methods something with the page number in them)

    I tried
    class Object
    def current_method
    caller[0][/in: `.+(pg_\d{3})/,1]
    end
    end

    but calls to this inside a method_missing method produce nil - not sure
    why, but obviously I need to study more ruby to understand why that
    doesn't work. Including current_method (as defined above) in module
    Kernel also doesn't do the trick, but having the caller[0][/in:
    `.+(pg_\d{3})/,1] inside the method_missing method works.

    Thanks for pointing me in the direction of a couple of new things
    Kev
     
    Kev Jackson, Mar 30, 2006
    #3
  4. Kev Jackson wrote:
    > Currently I have
    >
    > caller[0][/in: `.+(pg_\d{3})/,1]
    > which adequately returns the current method (given the current
    > convention of naming the methods something with the page number in them)
    >
    > I tried
    > class Object
    > def current_method
    > caller[0][/in: `.+(pg_\d{3})/,1]
    > end
    > end
    >
    > but calls to this inside a method_missing method produce nil - not sure
    > why, but obviously I need to study more ruby to understand why that
    > doesn't work. Including current_method (as defined above) in module
    > Kernel also doesn't do the trick, but having the caller[0][/in:
    > `.+(pg_\d{3})/,1] inside the method_missing method works.


    Maybe you're calling method_missing again? Could be that you a) either
    need to provide a parameter to current_method that determines how many
    levels to go up or b) you cannot do what you want because once
    method_missing is invoked your original method name is lost:

    >> o=Object.new

    => #<Object:0x3f3530>
    >> def o.method_missing(s,*a,&b) p caller; p s; end

    => nil
    >> def o.bar() foo() end

    => nil
    >> o.bar

    ["(irb):7:in `bar'", "(irb):8:in `irb_binding'",
    "/usr/lib/ruby/1.8/irb/workspace.rb:52:in `irb_binding'", ":0"]
    :foo
    => nil

    "foo" doesn't show up in caller, but method_missing has the symbol
    (first arg).

    > Thanks for pointing me in the direction of a couple of new things


    You're welcome!

    Kind regards

    robert
     
    Robert Klemme, Mar 30, 2006
    #4
  5. Kev Jackson

    Guest

    On Thu, 30 Mar 2006, Kev Jackson wrote:

    > Currently I have
    >
    > caller[0][/in: `.+(pg_\d{3})/,1]
    > which adequately returns the current method (given the current convention of
    > naming the methods something with the page number in them)
    >
    > I tried
    > class Object
    > def current_method
    > caller[0][/in: `.+(pg_\d{3})/,1]
    > end
    > end
    >
    > but calls to this inside a method_missing method produce nil - not sure why,
    > but obviously I need to study more ruby to understand why that doesn't work.
    > Including current_method (as defined above) in module Kernel also doesn't do
    > the trick, but having the caller[0][/in: `.+(pg_\d{3})/,1] inside the
    > method_missing method works.
    >
    > Thanks for pointing me in the direction of a couple of new things


    you could use metaprogramming to provide this functionality:

    harp:~ > cat a.rb
    class Thread
    attr_accessor 'where'
    end
    class Module
    require 'thread'
    def referable *methods
    methods.flatten.each do |m|
    module_eval <<-code
    alias_method "__#{ m }__", "#{ m }"
    def #{ m }(*a, &b)
    t = Thread.current
    where = t.where
    begin
    t.where = "#{ m }"
    __#{ m }__(*a, &b)
    ensure
    t.where = where
    end
    end
    code
    end
    end
    end
    class Object
    def where
    Thread.current.where
    end
    end

    #
    # eg
    #
    class << self
    def foo
    p where
    bar
    end
    def bar
    p where
    end
    referable 'foo', 'bar'
    end

    self.foo

    class C
    def method_missing(m, *a, &b)
    p where
    foo
    end
    def foo
    p where
    end
    referable 'method_missing', 'foo'
    end

    C.new.bar



    harp:~ > ruby a.rb
    "foo"
    "bar"
    "method_missing"
    "foo"


    regards.


    -a
    --
    share your knowledge. it's a way to achieve immortality.
    - h.h. the 14th dali lama
     
    , Mar 30, 2006
    #5
    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.

Share This Page