Making object methods available externally

Discussion in 'Ruby' started by David Stanford, Feb 4, 2009.

  1. Hi all,

    I'm having trouble figuring out a way of creating a method within a
    class that's available not only to the other object methods (object
    instances), but also externally, as if I were to use 'self.method'.
    Below is an (admittedly, lame) example of what I'm referring to:

    #############################

    class CheesePhrase
    def initialize(phrase)
    @phrase = phrase
    say_it
    end

    def say_it(phrase=@phrase)
    puts "#{phrase}"
    end
    end

    #############################

    The above code works fine if I create an object instance, and (if I
    choose to do so) call the method 'say_it', like so:

    some_cheese_phrase = CheesePhrase.new("I like cheese.")
    some_cheese_phrase.say_it

    However, what if I'd also like to call the method directly, without
    creating a new instance? For example, simply with:

    CheesePhrase.say_it("I like cheese, too.")

    I can't do this without using 'self.say_it' in the method declaration.
    Though, if I do that, I am no longer able to call the method in
    'initialize' since 'self.say_it' is now a class method. I get the
    following error:

    NoMethodError: undefined method `say_it' for #<CheesePhrase:0x284372f4
    @phrase="I like cheese">
    from (irb):4:in `initialize'
    from (irb):11:in `new'

    I'm sure I must be doing something wrong, or my concept of how to
    implement this is totally wrong. The only other thought I've had is to
    create duplicate methods, but this seems to violate the famed DRY
    principle. Any advice would be much appreciated.

    Thanks in advance!

    -David
    --
    Posted via http://www.ruby-forum.com/.
    David Stanford, Feb 4, 2009
    #1
    1. Advertising

  2. On Feb 4, 2009, at 1:37 PM, David Stanford wrote:

    > Hi all,
    >
    > I'm having trouble figuring out a way of creating a method within a
    > class that's available not only to the other object methods (object
    > instances), but also externally, as if I were to use 'self.method'.
    > Below is an (admittedly, lame) example of what I'm referring to:
    >
    > #############################
    >
    > class CheesePhrase
    > def initialize(phrase)
    > @phrase = phrase
    > say_it
    > end
    >
    > def say_it(phrase=@phrase)
    > puts "#{phrase}"
    > end
    > end
    >
    > #############################
    > <snip/>
    > Thanks in advance!
    >
    > -David


    class CheesePhrase
    def initialize(phrase)
    @phrase = phrase
    say_it
    end

    def self.say_it(phrase)
    puts phrase
    end
    def say_it
    self.class.say_it(@phrase)
    end
    end

    irb> some_cheese_phrase = CheesePhrase.new("I like cheese.")
    I like cheese.
    => #<CheesePhrase:0x629d0 @phrase="I like cheese.">
    irb> some_cheese_phrase.say_it
    I like cheese.
    => nil
    irb> CheesePhrase.say_it("I like cheese, too.")
    I like cheese, too.
    => nil

    -Rob

    Rob Biedenharn http://agileconsultingllc.com
    Rob Biedenharn, Feb 4, 2009
    #2
    1. Advertising

  3. Rob Biedenharn wrote:
    > On Feb 4, 2009, at 1:37 PM, David Stanford wrote:


    > class CheesePhrase
    > def initialize(phrase)
    > @phrase = phrase
    > say_it
    > end
    >
    > def self.say_it(phrase)
    > puts phrase
    > end
    > def say_it
    > self.class.say_it(@phrase)
    > end
    > end


    > -Rob
    >
    > Rob Biedenharn http://agileconsultingllc.com
    >


    Thanks a lot, Rob. Is this really the standard way of implementing
    something like this? It just seems a little redundant, no?

    Thanks!

    -David
    --
    Posted via http://www.ruby-forum.com/.
    David Stanford, Feb 4, 2009
    #3
  4. David Stanford

    Guest

    Hi David,
    i don't understand well what you need. Is this that you are looking for:
    class CheesePhrase
    def initialize(phrase)
    @phrase = phrase
    CheesePhrase.say_it(phrase)
    end
    def CheesePhrase.say_it(phrase=@phrase)
    puts "#{phrase}"
    end
    end

    a = CheesePhrase.new('I like cheese')
    a = CheesePhrase.say_it('I like too much cheese);

    On Thu, 5 Feb 2009 03:37:30 +0900, David Stanford <>
    wrote:
    > Hi all,
    >
    > I'm having trouble figuring out a way of creating a method within a
    > class that's available not only to the other object methods (object
    > instances), but also externally, as if I were to use 'self.method'.
    > Below is an (admittedly, lame) example of what I'm referring to:
    >
    > #############################
    >
    > class CheesePhrase
    > def initialize(phrase)
    > @phrase = phrase
    > say_it
    > end
    >
    > def say_it(phrase=@phrase)
    > puts "#{phrase}"
    > end
    > end
    >
    > #############################
    >
    > The above code works fine if I create an object instance, and (if I
    > choose to do so) call the method 'say_it', like so:
    >
    > some_cheese_phrase = CheesePhrase.new("I like cheese.")
    > some_cheese_phrase.say_it
    >
    > However, what if I'd also like to call the method directly, without
    > creating a new instance? For example, simply with:
    >
    > CheesePhrase.say_it("I like cheese, too.")
    >
    > I can't do this without using 'self.say_it' in the method declaration.
    > Though, if I do that, I am no longer able to call the method in
    > 'initialize' since 'self.say_it' is now a class method. I get the
    > following error:
    >
    > NoMethodError: undefined method `say_it' for #<CheesePhrase:0x284372f4
    > @phrase="I like cheese">
    > from (irb):4:in `initialize'
    > from (irb):11:in `new'
    >
    > I'm sure I must be doing something wrong, or my concept of how to
    > implement this is totally wrong. The only other thought I've had is to
    > create duplicate methods, but this seems to violate the famed DRY
    > principle. Any advice would be much appreciated.
    >
    > Thanks in advance!
    >
    > -David
    > --
    > Posted via http://www.ruby-forum.com/.
    , Feb 4, 2009
    #4
  5. On Feb 4, 2009, at 2:03 PM, David Stanford wrote:
    > Rob Biedenharn wrote:
    >> On Feb 4, 2009, at 1:37 PM, David Stanford wrote:

    >
    >> class CheesePhrase
    >> def initialize(phrase)
    >> @phrase = phrase
    >> say_it
    >> end
    >>
    >> def self.say_it(phrase)
    >> puts phrase
    >> end
    >> def say_it
    >> self.class.say_it(@phrase)
    >> end
    >> end

    >
    >> -Rob
    >>
    >> Rob Biedenharn http://agileconsultingllc.com
    >>

    >
    > Thanks a lot, Rob. Is this really the standard way of implementing
    > something like this? It just seems a little redundant, no?
    >
    > Thanks!
    >
    > -David



    When you need it, yes. However, it isn't typical that you'd do
    something like this. Either the method belongs on the instance or it
    belongs on the class itself. Occasionally, for convenience, you want
    a class method to be called on an instance and then you'd likely do it
    this way. Your example is simple (and, being an example, somewhat
    contrived), but illustrates a point. You can call #say_it with no
    parameter because the instance variable is there so an instance
    *knows* what to say, but to call .say_it on the class, you need to
    pass the parameter.

    -Rob

    Rob Biedenharn http://agileconsultingllc.com
    Rob Biedenharn, Feb 4, 2009
    #5
  6. [Note: parts of this message were removed to make it a legal post.]

    On Wed, Feb 4, 2009 at 3:06 PM, Rob Biedenharn
    <>wrote:

    >
    > When you need it, yes. However, it isn't typical that you'd do something
    > like this. Either the method belongs on the instance or it belongs on the
    > class itself. Occasionally, for convenience, you want a class method to be
    > called on an instance and then you'd likely do it this way. Your example is
    > simple (and, being an example, somewhat contrived), but illustrates a point.
    > You can call #say_it with no parameter because the instance variable is
    > there so an instance *knows* what to say, but to call .say_it on the class,
    > you need to pass the parameter.
    >


    Ruby does have a method Module#module_function which can be used in cases
    similar to this. For a rather silly example:

    module Test
    def foo
    puts "Foo"
    end

    module_function :foo
    end

    Test.foo

    begin
    foo
    rescue Exception => ex
    puts "oops! #{ex}"
    end

    self.extend Test
    foo

    when run produces:

    Foo
    oops! undefined local variable or method `foo' for main:Object
    Foo

    What module_function does is to copy one or more instance methods and make
    them singleton methods of the module. It only works for modules not
    classes.

    The canonical use case is in the Math module so that you can either write:

    Math.sin(.2)

    or

    class X
    include Math

    def compute(val)
    2 + sin(val)
    end
    end
    --
    Rick DeNatale

    Blog: http://talklikeaduck.denhaven2.com/
    Twitter: http://twitter.com/RickDeNatale
    Rick DeNatale, Feb 4, 2009
    #6
  7. Put "self." in front of the method name in it's definition. This is
    called a class method. If you need both, have both.

    Blog: http://random8.zenunit.com/
    Learn rails: http://sensei.zenunit.com/

    On 05/02/2009, at 5:37 AM, David Stanford <> wrote:

    > Hi all,
    >
    > I'm having trouble figuring out a way of creating a method within a
    > class that's available not only to the other object methods (object
    > instances), but also externally, as if I were to use 'self.method'.
    > Below is an (admittedly, lame) example of what I'm referring to:
    >
    > #############################
    >
    > class CheesePhrase
    > def initialize(phrase)
    > @phrase = phrase
    > say_it
    > end
    >
    > def say_it(phrase=@phrase)
    > puts "#{phrase}"
    > end
    > end
    >
    > #############################
    >
    > The above code works fine if I create an object instance, and (if I
    > choose to do so) call the method 'say_it', like so:
    >
    > some_cheese_phrase = CheesePhrase.new("I like cheese.")
    > some_cheese_phrase.say_it
    >
    > However, what if I'd also like to call the method directly, without
    > creating a new instance? For example, simply with:
    >
    > CheesePhrase.say_it("I like cheese, too.")
    >
    > I can't do this without using 'self.say_it' in the method declaration.
    > Though, if I do that, I am no longer able to call the method in
    > 'initialize' since 'self.say_it' is now a class method. I get the
    > following error:
    >
    > NoMethodError: undefined method `say_it' for #<CheesePhrase:0x284372f4
    > @phrase="I like cheese">
    > from (irb):4:in `initialize'
    > from (irb):11:in `new'
    >
    > I'm sure I must be doing something wrong, or my concept of how to
    > implement this is totally wrong. The only other thought I've had is to
    > create duplicate methods, but this seems to violate the famed DRY
    > principle. Any advice would be much appreciated.
    >
    > Thanks in advance!
    >
    > -David
    > --
    > Posted via http://www.ruby-forum.com/.
    >
    Julian Leviston, Feb 5, 2009
    #7
  8. Thanks for all the responses, guys.

    Judging from everyone's response, it sounds like what I'm trying to do
    isn't typically done. My mindset was, first, to simply create a standard
    class. While creating one of the object methods for that class, I
    realized that the same method code would be useful to call directly,
    without having to create an object instance; so, as I said, I was
    thinking there must be some way to do this, without repeating the same
    (or a similar piece) of code somewhere else.

    So, thanks again!
    --
    Posted via http://www.ruby-forum.com/.
    David Stanford, Feb 5, 2009
    #8
  9. David Stanford

    Mike Gold Guest

    Rick Denatale wrote:
    > Ruby does have a method Module#module_function which can be used in
    > cases similar to this. For a rather silly example:
    >
    > module Test
    > def foo
    > puts "Foo"
    > end
    >
    > module_function :foo
    > end


    To make a minor point, I see this use of module_function often, even in
    the standard library. I don't like it.

    In addition to the module_function method, there's the module_function
    scoping state, like public or private or protected, which is likewise
    enabled by calling module_function without arguments. Therefore we can
    make a D.R.Y. equivalent:

    module Test
    module_function

    def foo
    puts "Foo"
    end
    end
    --
    Posted via http://www.ruby-forum.com/.
    Mike Gold, Feb 6, 2009
    #9
  10. 2009/2/5 David Stanford <>:

    > Judging from everyone's response, it sounds like what I'm trying to do
    > isn't typically done.


    Agreed.

    > My mindset was, first, to simply create a standard
    > class. While creating one of the object methods for that class, I
    > realized that the same method code would be useful to call directly,
    > without having to create an object instance; so, as I said, I was
    > thinking there must be some way to do this, without repeating the same
    > (or a similar piece) of code somewhere else.


    In that case I would have the method definition *only* at class level
    since apparently it is independent of instance state. I wouldn't even
    have it as instance method at all. That avoids confusion. If you
    need to invoke the method from instance methods the
    self.class.a_method() idiom works well IMHO.

    Kind regards

    robert

    --
    remember.guy do |as, often| as.you_can - without end
    Robert Klemme, Feb 6, 2009
    #10
  11. David Stanford

    Roger Pack Guest

    David Stanford wrote:
    > Hi all,
    >
    > I'm having trouble figuring out a way of creating a method within a
    > class that's available not only to the other object methods (object
    > instances), but also externally, as if I were to use 'self.method'.


    you could do something like
    module X
    def shared_method
    end
    end
    class Y
    include X
    extend X
    end
    ?
    -=r
    --
    Posted via http://www.ruby-forum.com/.
    Roger Pack, Feb 7, 2009
    #11
  12. On Thu, Feb 5, 2009 at 5:31 PM, David Stanford <> wrote:
    > Thanks for all the responses, guys.
    >
    > Judging from everyone's response, it sounds like what I'm trying to do
    > isn't typically done. My mindset was, first, to simply create a standard
    > class. While creating one of the object methods for that class, I
    > realized that the same method code would be useful to call directly,
    > without having to create an object instance; so, as I said, I was
    > thinking there must be some way to do this, without repeating the same
    > (or a similar piece) of code somewhere else.


    Probably s bit extreme for one method, but say you had 10 you wanted
    to do this with:

    module Foo
    def self.included(base)
    base.extend(self)
    end

    def method1; end
    def method2; end
    #...
    end

    class A
    include Foo # no need for manual extend call
    end

    Not tested or necessarily recommended. :)

    -greg

    --
    Technical Blaag at: http://blog.majesticseacreature.com
    Non-tech stuff at: http://metametta.blogspot.com
    "Ruby Best Practices" Book now in O'Reilly Roughcuts:
    http://rubybestpractices.com
    Gregory Brown, Feb 7, 2009
    #12
  13. On Fri, Feb 6, 2009 at 6:58 AM, Robert Klemme
    <> wrote:
    > 2009/2/5 David Stanford <>:
    >
    >> Judging from everyone's response, it sounds like what I'm trying to do
    >> isn't typically done.

    >
    > Agreed.
    >
    >> My mindset was, first, to simply create a standard
    >> class. While creating one of the object methods for that class, I
    >> realized that the same method code would be useful to call directly,
    >> without having to create an object instance; so, as I said, I was
    >> thinking there must be some way to do this, without repeating the same
    >> (or a similar piece) of code somewhere else.

    >
    > In that case I would have the method definition *only* at class level
    > since apparently it is independent of instance state. I wouldn't even
    > have it as instance method at all. That avoids confusion. If you
    > need to invoke the method from instance methods the
    > self.class.a_method() idiom works well IMHO.



    I think that depends on why the method is useful at both places; one
    thing I've seen occasionally is the use case where it is useful at the
    class level because there are lots of times you'd like to create an
    instance, call the method, and then be done with the instance, so it
    makes sense to have something like:

    class Foo
    def initialize(init_arg1, ..., init_argn)
    # setup
    end

    def action(action_arg1, ..., action_argn)
    # do the action
    end

    def self.action(init_arg1, ..., init_argn, action_arg1, ..., action_argn)
    new(init_arg1, ..., init_argn).action(action_arg1, ..., action_argn)
    end
    end

    If that's the reason, using the CheesePhrase example:

    class CheesePhrase
    # all the stuff in the original example
    def self.say_it(phrase)
    new(phrase).say_it
    end
    end
    Christopher Dicely, Feb 7, 2009
    #13
  14. * David Stanford <> (2009-02-04) schrieb:

    > Rob Biedenharn wrote:
    >> On Feb 4, 2009, at 1:37 PM, David Stanford wrote:

    >
    >> class CheesePhrase
    >> def initialize(phrase)
    >> @phrase = phrase
    >> say_it
    >> end
    >>
    >> def self.say_it(phrase)
    >> puts phrase
    >> end
    >> def say_it
    >> self.class.say_it(@phrase)
    >> end
    >> end


    > Thanks a lot, Rob. Is this really the standard way of implementing
    > something like this? It just seems a little redundant, no?


    Where do you see the redundancy? Nothing is repeated.

    mfg, simon .... l
    Simon Krahnke, Feb 7, 2009
    #14
    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. Marshal Antony
    Replies:
    2
    Views:
    1,076
    Amir Eshterayeh
    Feb 27, 2004
  2. Paul Kirby

    Externally Linking

    Paul Kirby, Jun 28, 2004, in forum: C++
    Replies:
    7
    Views:
    344
    Paul Kirby
    Jun 29, 2004
  3. Dean Harper

    jboss will not work externally

    Dean Harper, Jun 12, 2006, in forum: Java
    Replies:
    0
    Views:
    422
    Dean Harper
    Jun 12, 2006
  4. Marc
    Replies:
    2
    Views:
    306
    Andrew Dalke
    Oct 13, 2003
  5. King
    Replies:
    2
    Views:
    246
Loading...

Share This Page