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.
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
some_cheese_phrase = CheesePhrase.new("I like cheese.")
I like cheese.
=> #<CheesePhrase:0x629d0 @phrase="I like cheese.">
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 <dthomas53@hotmail.com> 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.
On 05/02/2009, at 5:37 AM, David Stanford <dthomas53@hotmail.com> 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.
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
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.
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.
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
···
2009/2/5 David Stanford <dthomas53@hotmail.com>:
--
remember.guy do |as, often| as.you_can - without end
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
···
On Thu, Feb 5, 2009 at 5:31 PM, David Stanford <dthomas53@hotmail.com> 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.
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
···
On Wed, Feb 4, 2009 at 3:06 PM, Rob Biedenharn <Rob@agileconsultingllc.com>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.
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
···
On Fri, Feb 6, 2009 at 6:58 AM, Robert Klemme <shortcutter@googlemail.com> wrote:
2009/2/5 David Stanford <dthomas53@hotmail.com>:
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.
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: