accessing methods from the blocks caller

Discussion in 'Ruby' started by andrew, Mar 18, 2007.

  1. andrew

    andrew Guest

    Hello,

    Sorry if this has been asked many times before, but I'm having a hard time
    finding the right keywords to search for this one.

    Here's my question... if I have a method that accepts a block and I want to
    call a method of the class I'm in, in that block, how do I do it? See the
    comment below in the example. Should make that sentence a bit clearer. :)

    class Test
    def method1
    end

    def method2
    accept_block do # accept_block is not part of the Test class
    ...
    method1 # I want to call method1 from the class I'm in, but
    I'm getting undefined method for method1
    ...
    end
    end
    end

    I understand why I would be getting this error, but I don't know how to fix
    it. Is there a way to access the caller in the block in order to access the
    method of it? Kernel.caller is the closest I found, but it's not what I
    want.

    I hope this makes some sense. The example is a bit contrived, but hopefully
    I get the point across.

    Thanks,
    Andrew
     
    andrew, Mar 18, 2007
    #1
    1. Advertising

  2. andrew

    andrew Guest

    Taking a better look at my pickaxe book, it seems as though this is simply a
    scoping issue that doesn't really have a solution. I have a workaround, but
    was curious to know if there was a "proper" way to accomplish what I was
    looking for.

    Thanks,
    Andrew

    "andrew" <> wrote in message
    news:w44Lh.32606$zU1.24952@pd7urf1no...
    > Hello,
    >
    > Sorry if this has been asked many times before, but I'm having a hard time
    > finding the right keywords to search for this one.
    >
    > Here's my question... if I have a method that accepts a block and I want
    > to call a method of the class I'm in, in that block, how do I do it? See
    > the comment below in the example. Should make that sentence a bit
    > clearer. :)
    >
    > class Test
    > def method1
    > end
    >
    > def method2
    > accept_block do # accept_block is not part of the Test class
    > ...
    > method1 # I want to call method1 from the class I'm in, but
    > I'm getting undefined method for method1
    > ...
    > end
    > end
    > end
    >
    > I understand why I would be getting this error, but I don't know how to
    > fix it. Is there a way to access the caller in the block in order to
    > access the method of it? Kernel.caller is the closest I found, but it's
    > not what I want.
    >
    > I hope this makes some sense. The example is a bit contrived, but
    > hopefully I get the point across.
    >
    > Thanks,
    > Andrew
    >
     
    andrew, Mar 18, 2007
    #2
    1. Advertising

  3. andrew

    eden li Guest

    In the three cases I could think of, "method1" was always available to
    the block. AFAIK, the block you pass to #accept_block no matter where
    it is will always be bound to the lexical context you call it in,
    meaning that 'method1' will always be available unless you do
    something special when you call the block.

    Maybe it'll help if you list the source for #accept_block and the
    exact error you're getting.

    # case 1, 'accept_block' defined in a super class
    class S
    def foo; yield; end
    end

    # case 2, 'accept_block' defined in an included module
    module M
    def bar; yield; end
    end

    # case 3, 'accept_block' defined in some other class
    class D
    def baz; yield; end
    end

    class C < S
    include M
    def m1; 'hi'; end
    def test_foo; foo { m1 }; end
    def test_bar; bar { m1 }; end
    def test_baz; D.new.baz { m1 }; end
    end

    >> c = C.new

    => #<C:0xb7c396e8>
    >> c.test_foo

    => "hi"
    >> c.test_bar

    => "hi"
    >> c.test_baz

    => "hi"

    On Mar 18, 1:30 pm, "andrew" <> wrote:
    > Here's my question... if I have a method that accepts a block and I want to
    > call a method of the class I'm in, in that block, how do I do it? See the
    > comment below in the example. Should make that sentence a bit clearer. :)
    >
    > class Test
    > def method1
    > end
    >
    > def method2
    > accept_block do # accept_block is not part of the Test class
    > ...
    > method1 # I want to call method1 from the class I'm in, but
    > I'm getting undefined method for method1
    > ...
    > end
    > end
    > end
    >
    > I understand why I would be getting this error, but I don't know how to fix
    > it. Is there a way to access the caller in the block in order to access the
    > method of it? Kernel.caller is the closest I found, but it's not what I
    > want.
     
    eden li, Mar 18, 2007
    #3
  4. andrew

    eden li Guest

    $ irb
    irb(main):001:0> class Test; def method1; end; def method2;
    accept_block { method1 }; end; end
    => nil
    irb(main):002:0> def accept_block; yield; end
    => nil
    irb(main):003:0> Test.new.method2
    => nil

    No error... there's something weird going on with your version of
    #accept_block. Care to dump the source out here?

    On Mar 18, 3:55 pm, "andrew" <> wrote:
    > Taking a better look at my pickaxe book, it seems as though this is simply a
    > scoping issue that doesn't really have a solution. I have a workaround, but
    > was curious to know if there was a "proper" way to accomplish what I was
    > looking for.
    >
    > Thanks,
    > Andrew
    >
    > "andrew" <> wrote in message
    >
    > news:w44Lh.32606$zU1.24952@pd7urf1no...
    >
    > > Hello,

    >
    > > Sorry if this has been asked many times before, but I'm having a hard time
    > > finding the right keywords to search for this one.

    >
    > > Here's my question... if I have a method that accepts a block and I want
    > > to call a method of the class I'm in, in that block, how do I do it? See
    > > the comment below in the example. Should make that sentence a bit
    > > clearer. :)

    >
    > > class Test
    > > def method1
    > > end

    >
    > > def method2
    > > accept_block do # accept_block is not part of the Test class
    > > ...
    > > method1 # I want to call method1 from the class I'm in, but
    > > I'm getting undefined method for method1
    > > ...
    > > end
    > > end
    > > end

    >
    > > I understand why I would be getting this error, but I don't know how to
    > > fix it. Is there a way to access the caller in the block in order to
    > > access the method of it? Kernel.caller is the closest I found, but it's
    > > not what I want.

    >
    > > I hope this makes some sense. The example is a bit contrived, but
    > > hopefully I get the point across.

    >
    > > Thanks,
    > > Andrew
     
    eden li, Mar 18, 2007
    #4
  5. On Sun, Mar 18, 2007 at 02:30:04PM +0900, andrew wrote:
    > class Test
    > def method1
    > end
    >
    > def method2
    > accept_block do # accept_block is not part of the Test class
    > ...
    > method1 # I want to call method1 from the class I'm in, but I'm getting undefined method for method1
    > ...
    > end
    > end
    > end
    >
    > I understand why I would be getting this error, but I don't know how to fix
    > it. Is there a way to access the caller in the block in order to access the
    > method of it? Kernel.caller is the closest I found, but it's not what I
    > want.


    As people have said, this *should* work. Post a complete example where it
    fails, and the error message.

    Having said that, if there is a need to, the current object is called 'self'
    and can be passed around explicitly if you wish:

    class Test
    def accept_block(some_object)
    yield some_object
    end

    def method1
    puts "whoo!"
    end

    def method2
    accept_block(self) do |s|
    # ...
    s.method1
    # ...
    end
    end
    end
    Test.new.method2 # prints "whoo!"

    ---- But this particular example works without:

    class Test
    def accept_block
    yield
    end

    def method1
    puts "whoo!"
    end

    def method2
    accept_block do
    # ...
    method1
    # ...
    end
    end
    end
    Test.new.method2 # prints "whoo!"

    Regards,

    Brian.
     
    Brian Candler, Mar 18, 2007
    #5
  6. andrew

    andrew Guest

    I'm experiencing the issue using Rails. I wanted to leave mention of Rails
    out of my post as I figured it was simply a Ruby issue, but perhaps not.

    class MyController < ApplicationController
    def some_action
    render :update do |page|
    render_to_string # getting an error that render_to_string
    is undefined
    end
    end
    end

    I fix this by doing this...
    def some_action
    str = render_to_string
    render :update to |page|
    # use str in the block
    end
    end

    So for anybody with a bit of rails knowledge, do you know what's going on?
    I can ask this in a rails group now if you think it's off topic.

    Thanks again,
    Andrew

    "eden li" <> wrote in message
    news:...
    > In the three cases I could think of, "method1" was always available to
    > the block. AFAIK, the block you pass to #accept_block no matter where
    > it is will always be bound to the lexical context you call it in,
    > meaning that 'method1' will always be available unless you do
    > something special when you call the block.
    >
    > Maybe it'll help if you list the source for #accept_block and the
    > exact error you're getting.
    >
    > # case 1, 'accept_block' defined in a super class
    > class S
    > def foo; yield; end
    > end
    >
    > # case 2, 'accept_block' defined in an included module
    > module M
    > def bar; yield; end
    > end
    >
    > # case 3, 'accept_block' defined in some other class
    > class D
    > def baz; yield; end
    > end
    >
    > class C < S
    > include M
    > def m1; 'hi'; end
    > def test_foo; foo { m1 }; end
    > def test_bar; bar { m1 }; end
    > def test_baz; D.new.baz { m1 }; end
    > end
    >
    >>> c = C.new

    > => #<C:0xb7c396e8>
    >>> c.test_foo

    > => "hi"
    >>> c.test_bar

    > => "hi"
    >>> c.test_baz

    > => "hi"
    >
    > On Mar 18, 1:30 pm, "andrew" <> wrote:
    >> Here's my question... if I have a method that accepts a block and I want
    >> to
    >> call a method of the class I'm in, in that block, how do I do it? See
    >> the
    >> comment below in the example. Should make that sentence a bit clearer.
    >> :)
    >>
    >> class Test
    >> def method1
    >> end
    >>
    >> def method2
    >> accept_block do # accept_block is not part of the Test class
    >> ...
    >> method1 # I want to call method1 from the class I'm in,
    >> but
    >> I'm getting undefined method for method1
    >> ...
    >> end
    >> end
    >> end
    >>
    >> I understand why I would be getting this error, but I don't know how to
    >> fix
    >> it. Is there a way to access the caller in the block in order to access
    >> the
    >> method of it? Kernel.caller is the closest I found, but it's not what I
    >> want.

    >
    >
     
    andrew, Mar 18, 2007
    #6
  7. On Mon, Mar 19, 2007 at 05:20:05AM +0900, andrew wrote:
    > I'm experiencing the issue using Rails. I wanted to leave mention of Rails
    > out of my post as I figured it was simply a Ruby issue, but perhaps not.
    >
    > class MyController < ApplicationController
    > def some_action
    > render :update do |page|
    > render_to_string # getting an error that render_to_string
    > is undefined
    > end
    > end
    > end
    >
    > I fix this by doing this...
    > def some_action
    > str = render_to_string
    > render :update to |page|
    > # use str in the block
    > end
    > end


    This is a rails issue. The *controller* and the *view* are two separate
    objects; methods defined in the controller are not by default available in
    the view.

    The preferred solution is usually to define render_to_string as a helper in
    app/helpers/mys.rb (as long as it's needed only by the view, not by the
    controller itself)

    If you must define it in the controller for some reason, then you can make
    it available in the view by

    def render_to_string
    ...
    end
    helper_method :render_to_string

    > I can ask this in a rails group now if you think it's off topic.


    It's definitely a rails issue - further questions would best be asked there.

    Regards,

    Brian.
     
    Brian Candler, Mar 18, 2007
    #7
  8. On Mon, Mar 19, 2007 at 05:40:45AM +0900, Brian Candler wrote:
    > This is a rails issue. The *controller* and the *view* are two separate
    > objects; methods defined in the controller are not by default available in
    > the view.
    >
    > The preferred solution is usually to define render_to_string as a helper in
    > app/helpers/mys.rb (as long as it's needed only by the view, not by the
    > controller itself)
    >
    > If you must define it in the controller for some reason, then you can make
    > it available in the view by
    >
    > def render_to_string
    > ...
    > end
    > helper_method :render_to_string


    Alternatively: I think that *public* methods in the controller can be
    accessed from within the view by using the 'controller' accessor. e.g.

    <%= controller.render_to_string %>

    But this is probably not a good idea if render_to_string is a method which
    you don't want to make available to the outside world (in which case you
    should mark it 'private')

    B.
     
    Brian Candler, Mar 18, 2007
    #8
    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. Arjen
    Replies:
    3
    Views:
    453
    Scott Allen
    Feb 27, 2005
  2. matt
    Replies:
    1
    Views:
    284
    George Ogata
    Aug 6, 2004
  3. Ben Bleything

    accessing caller's binding implicitly

    Ben Bleything, Nov 10, 2006, in forum: Ruby
    Replies:
    5
    Views:
    119
    Ben Bleything
    Nov 10, 2006
  4. Steven Taylor
    Replies:
    9
    Views:
    270
    Brian Candler
    Apr 27, 2009
  5. Mark
    Replies:
    2
    Views:
    406
Loading...

Share This Page