I want to add a foo method to Ruby's Kernel module, so I can write foo(obj) anywhere and have it do something to obj. Sometimes I want a class to override foo, so I do this:
module Kernel
private # important; this is what Ruby does for commands like 'puts', etc.
def foo x
if x.respond_to? :foo
x.foo # use overwritten method.
else
# do something to x.
end
end
end
this is good, and works. but, what if I want to use the default Kernel::foo in some other object that overwrites foo? Since I've got an instance method foo, I've lost the original binding to Kernel::foo.
class Bar
def foo # override behaviour of Kernel::foo for Bar objects.
foo(3) # calls Bar::foo, not the desired call of Kernel::foo.
Kernel::foo(3) # can't call Kernel::foo because it's private.
# question: how do I call Kernel::foo on 3?
end
end
Is there any clean way to get around this? I'd rather not have two different names, and I definitely don't want to make Kernel::foo public.
You can use the super keyword to call the superclass's implementation from a overridden method.
class Bar
def foo # override behaviour of Kernel::foo for Bar objects.
super
# do something else here
end
end
For a more general solution than just super (super wont always work), also see this thread:
How to access a shadowed global function in Ruby?
Just use alias or alias_method before you redefine Kernel.foo to keep a reference to the original version.
Related
The methods in Math can be invoked like a class method:
Math.cos(0)
but also can be include-d like instance method:
include Math
cos(0)
In contrast, the following modules can be invoked in one way but not the other:
module Foo
def bar
end
end
Foo.bar() # NoMethodError for this call
include Foo
bar() # but this call is fine
Singleton method:
module Foo
def self.bar
end
end
Foo.bar() # this call is fine
include Foo
bar() # but not this one
Any idea how to write a module like Math?
There're a few ways to get singleton methods, so I'm going to go over those first. We'll get to the part that lets the include Math work in a minute. So, first, if you're in a module or class body, you can define a singleton method as a method of self, like so:
module Foo
# Define bar as a method on self (the Foo module), thereby making
# it a singleton method.
def self.bar
"baz"
end
end
Alternatively, you can define them as methods on a module or class's singleton class:
module Foo
# Opens the singleton class of self (the Foo module). This makes
# bar a singleton method (see Module#define_singleton_method for
# some more on that).
class <<self
def bar
"baz"
end
end
end
include Math, Having Your Methods, and Eating Them Too
Thirdly, if you want methods as both instance and singleton methods, you can use extend. This allows you to include the module somewhere and call its methods without qualification or at least with differing qualification, depending on where you include the module (sort of -- that's beyond the scope of this, though). You can also extend self or extend using another module (containing instance methods) to add them as singleton methods when in a module or class body. This might sound more complicated than it probably looks:
module Foo
def bar
"baz"
end
# Extending self will add the instance methods of self as
# methods on the object self -- which happens to be a module,
# so you basically get class methods from the instance methods.
extend self
end
This last case allows you to also include the module in another module or class and gain bar as an instance method as well, so what you do depends on what you need. In general, I prefer the first route if I'm just defining a singleton method and it's all I'll need. The second option is more or less equivalent, but also allows you to use alias_method and so on. Qualified access is next to godliness, as far as I'm concerned.
The third option, however, — using extend self — is good for doing what you're asking about with include Math, where you want to be able to both call a function as a singleton method (Math.cos(0)) and include the module to access and call the methods without qualifying them with the module name (cos(0)). If you want that, you can do one of the following:
Define the method twice, both as a singleton method and as an instance method. This is not preferrable.
Define them in another module and both include and extend using that module. This is handy if you want to use the module in multiple places.
extend self. Extending using self is probably the best choice here, since it's simple, reduces duplicate code, and it's sufficient for the purpose of the question.
So there you go, instance methods and singleton methods living side-by-side in harmony, just like Holan and Hamlet.
That's what Module#module_function is for.
RSpec adds a "describe" method do the top-level namespace. However, instead of simply defining the method outside of any classes/modules, they do this:
# code from rspec-core/lib/rspec/core/dsl.rb
module RSpec
module Core
# Adds the `describe` method to the top-level namespace.
module DSL
def describe(*args, &example_group_block)
RSpec::Core::ExampleGroup.describe(*args, &example_group_block).register
end
end
end
end
extend RSpec::Core::DSL
Module.send(:include, RSpec::Core::DSL)
What is the benefit of using this technique as opposed to simply defining describe outside any modules and classes? (From what I can tell, the DSL module isn't used anywhere else in rspec-core.)
I made this change a few months ago so that describe is no longer added to every object in the system. If you defined it at the top level:
def describe(*args)
end
...then every object in the system would have a private describe method. RSpec does not own every object in the system and should not be adding describe willy-nilly to every object. We only want the describe method available in two scopes:
describe MyClass do
end
(at the top-level, off of the main object)
module MyModule
describe MyClass do
end
end
(off of any module, so you nest your describes in a module scope)
Putting it in a module makes it easy to extend onto the main object (to add it to only that object, and not every object) and include it in Module (to add it to all modules).
Actually, if that's all there is in the code, I don't really believe it to be much better — if at all. A common argument is that you can easily check that RSpec is responsible for addinng this method in the global namespace by checking the method owner. Somehow it never felt this was needed, as the location of the method already stores that information.
Defining the method outside of any scope would have be equivalent to defining a private instance method in Object:
class Object
private
def double(arg)
arg * 2
end
end
double(3) # OK
3.double(3) # Error: double is private
self.double(3) # Error: double is private
I think privateness is a useful aspect, because it prevents from making certain method calls that have no meaning, that the code shown in the question lacks.
There's an advantge to defining the method in a module, though, but the RSpec code doesn't seem to make use of it: using module_function, not only do you preserve privateness of the instance method, but you also get a public class method. This means that if you have an instance method of the same name, you will still be able to refer to the one defined by the module, by using the class method version.
A common example of module_function is the Kernel module, which contains most function-like core methods like puts (another one is Math). If you're in a class that redefines puts, you can still use Kernel#puts explicitly if you need:
class LikeAnIO
def puts(string)
#output << string
end
def do_work
puts "foo" # inserts "foo" in #output
Kernel.puts "foo" # inserts "foo" in $stdout
end
end
I have a Pointer class with a single attribute :contents, that points to an object of class MyObject.
class MyObject
def hello; "hello" end
end
class Pointer
attr_reader :contents
def initialize( cont ); #contents = cont end
# perhaps define some more state
end
I want my Pointer to be able to make copies of itself. I know that #dup method is defined by default, while #clone method is expected to be overriden to be able to make deep copies. But here, the copies don't have to be too deep. So, the first dilemma that I have is, should I override #dup method, because I don't really want to copy the additional state of my Pointer, just make a new one pointing to the same MyObject instance? Or should I refrain from overridine #dup, because I am not "supposed to" and override #clone with a method making shallow copies?
I would welcome comments on the above, but let's say that I will choose to override #dup. I could do just this:
class Pointer
def dup; self.class.new( contents ) end
end
But online, I read something like "the dup method will call the initialize copy method". Also, this guy writes about #initialize_clone, #initialize_dup and #initialize_copy in Ruby. That leaves me wondering, is the best practice perhaps like this?
class Pointer
def initialize_copy
# do I don't know what
end
end
Or like this?
class Pointer
def initialize_dup
# do I don't know what
end
end
Or should I just forget about online rants written to confuse beginners and go for overriding #dup without concerns?
Also, I do understand that I can just call #dup without defining any custom #dup, but what if I want to define #dup with different behavior?
Also, the same question apply to #clone - should I try to define #initialize_clone or just #clone?
From my experience, overloading #initialize_copy works just fine (never heard about initialize_dup and initialize_clone).
The original initialize_copy (which initializes every instance variable with the values from the original object) is available through super, so I usually do:
class MyClass
def initialize_copy(orig)
super
# Do custom initialization for self
end
end
I have an object like this
class SomeObject
def initialize &block
# do something
end
end
class AnotherObject < SomeObject
def initalize &block
super
# do something with block
end
end
When super is called in AnotherObject, the block seems to be passed to SomeObject. Is this the right behaviour and is there away round it?
According to rubyspec this is the correct behaviour, even if you pass explicit arguments to super (i.e. super('foo'))
If you don't want to pass that block, you could just pass a block that does nothing, although this isn't quite the same thing (e.g. if the method changes its behaviour based on block_given?)
It appears that
super(&nil)
is a way to pass no block at all to super, although I couldn't find this in ruby spec.
In Ruby, super is a keyword rather than a method.
Why was it designed this way?
Ruby's design tends toward implementing as much as possible as methods; keywords are usually reserved for language features that have their own grammar rules. super, however, looks and acts like a method call.
(I know it would be cumbersome to implement super in pure Ruby, since it would have to parse the method name out of caller, or use a trace_func. This alone wouldn't prevent it from being a method, because plenty of Kernel's methods are not implemented in pure Ruby.)
It behaves a little differently, in that if you don't pass arguments, all of the current arguments (and block, if present) are passed along... I'm not sure how that would work as a method.
To give a rather contrived example:
class A
def example(a, b, c)
yield whatever(a, b) + c
end
end
class B < A
def example(a, b, c)
super * 2
end
end
I did not need to handle the yield, or pass the arguments to super. In the cases where you specifically want to pass different arguments, then it behaves more like a method call. If you want to pass no arguments at all, you must pass empty parentheses (super()).
It simply doesn't have quite the same behaviour as a method call.
super doesn't automatically call the parent class's method. If you imagine the inheritance hierarchy of a ruby class as a list, with the class at the bottom and Object at the top, when ruby sees the the super keyword, rather than just check the the parent class, it moves up the entire list until it finds the first item that has a method defined with that name.
I'm careful to say item because it could also be a module. When you include a module in to a class, it is wrapped in an anonymous superclass and put above your class in the list I talked about before, so that means if you had a method defined for your class that was also defined in the module, then calling super from the class's implementation would call the module's implementation, and not the parent class's:
class Foo
def f
puts "Foo"
end
end
module Bar
def f
puts "Bar"
super
end
end
class Foobar < Foo
include Bar
def f
puts "Foobar"
super
end
end
foobar = Foobar.new
foobar.f
# =>
# Foobar
# Bar
# Foo
And I don't believe that it is possible to access this 'inheritance list' from the ruby environment itself, which would mean this functionality would not be available (However useful it is; I'm not every sure if this was an intended feature.)
Hm, good qustion. I'm not sure how else (besides using super) you would you reference the super version of a given method.
You can't simply call the method by name, because the way that polymorphism works (how it figures out which version of that method to actually call, based on the object class) would cause your method to call itself, spinning into an infinite set of calls, and resulting in a stack overflow.