Detecting that a method was not overridden - ruby

Say, I have the following 2 classes:
class A
def a_method
end
end
class B < A
end
Is it possible to detect from within (an instance of) class B that method a_method is only defined in the superclass, thus not being overridden in B?
Update: the solution
While I have marked the answer of Chuck as "accepted", later Paolo Perrota made me realize that the solution can apparently be simpler, and it will probably work with earlier versions of Ruby, too.
Detecting if "a_method" is overridden in B:
B.instance_methods(false).include?("a_method")
And for class methods we use singleton_methods similarly:
B.singleton_methods(false).include?("a_class_method")

If you're using Ruby 1.8.7 or above, it's easy with Method#owner/UnboundMethod#owner.
class Module
def implements_instance_method(method_name)
instance_method(method_name).owner == self
rescue NameError
false
end
end

class A
def m1; end
def m2; end
end
class B < A
def m1; end
def m3; end
end
obj = B.new
methods_in_class = obj.class.instance_methods(false) # => ["m1", "m3"]
methods_in_superclass = obj.class.superclass.instance_methods(false) # => ["m2", "m1"]
methods_in_superclass - methods_in_class # => ["m2"]

you can always to the following and see if its defined there:
a = A.new
a.methods.include?(:method)

Given an object b which is an instance of B, you can test to see whether b's immediate superclass has a_method:
b.class.superclass.instance_methods.include? 'a_method'
Notice that the test is against the method name, not a symbol or a method object.
"thus not being overridden in B" - Just knowing that the method is only defined in A is difficult because you can define the method on an individual instances of A and B... so I think it's going to be difficult to test that a_method is only defined on A, because you'd have to round up all the subclasses and subinstances in the system and test them...

Related

Dynamically define a super method for an instance of a class in Ruby

Say we have a class that we cannot change,
class C
def foo
super
puts "Low!"
end
end
We'll need to dynamically define the method foo in something that we'll be able to inject into C's ancestry chain. The behavior of super must be specific to a given object, not class-wide. We'll be able to enclose that logic into an anonymous module (let's name it for now):
module M
def foo
puts "High!"
end
end
Extending an instance of C with the module:
c = C.new
c.extend(M)
c.foo
# High!
will not work since we've put the method from the module before the method we've defined in the class. Looking at our object's ancestors
c.singleton_class.ancestors
# => [#<Class:#<C:0x00005652be630b20>>, M, C, ...]
I came up with an ugly workaround, which is redefining the methods from our class in our singleton_class, i.e.
c.define_singleton_method(:foo, c.class.instance_method(:foo))
c.foo
# High!
# Low!
While this works (does it work? I've tested it for a bit and it seems to, but I'm no longer certain), I wonder whether I'm missing something obvious and there's an easier way to dynamically define a "super" method for an instance of a class.
To be clear, we want to be able to extend another instance of C with another module, i.e.
C.new.extend(Module.new do
def foo
puts "Medium!"
end
end).foo
# Medium!
# Low!
and have its output not tainted by other instances.
Now that I understand you're trying to work around an issue in some third-party code, I can suggest a more reasonable solution. In the code below, I'm thinking that B and C are defined by the gem and you don't want to change their source code, but you want to inject some code into the place where C#foo calls B#foo.
class B
def foo
puts "Highest!"
end
end
class C < B
def foo
super
puts "Low!"
end
end
module CE
def foo
super
foo_injected
end
end
C.include(CE)
module M
def foo_injected
puts "High!"
end
end
c = C.new
c.extend(M)
p c.singleton_class.ancestors
c.foo
The output is:
[#<Class:#<C:0x000055ce443366a8>>, M, C, CE, B, Object, Kernel, BasicObject]
Highest!
High!
Low!

Usage of "self", mixin methods, and exposed methods

This is some code that I use in a class called Game:
def play
puts "There are #{#players.length} players in #{#title}."
#players.each do |n|
puts n
end
#players.each do |o|
GameTurn.take_turn(o)
puts o
end
end
It uses a line of code that references a module called GameTurn. Within GameTurn, I have a method called self.take_turn:
require_relative "die"
require_relative "Player"
module GameTurn
def self.take_turn(o)
die = Die.new
case die.roll
when 1..2
o.blam
puts "#{o.name} was blammed homie."
when 3..4
puts "#{o.name} was skipped."
else
o.w00t
end
end
end
I'm a little confused why we use "self" and the difference between exposed methods and mixin methods in modules. I asked this "instance methods of classes vs module methods"
Is take_turn really an exposed method? Even though we're feeding into the take_turn method an object from the player class, is this method still considered a module method that we're using directly? Is this not considered a mixin method? We are feeding into the take_turn method an object from another class, so isn't it mixing in with other classes?
Also, I am still trying to figure out when/why we use the term "self"? It just seems weird that we need to define the method take_turn within the GameTurn module using the term "self". It seems like it should be defined without "self" no?
Ok, from the start:
self always returns the object in which context it is executed. So here:
class A
self #=> A
end
In ruby, you can define methods on objects in flight, you can for example do:
o = Object.new
o.foo #=> NameError
def o.foo
:foo
end
o.foo #=> :foo
Classes and modules are just objects as everything else, hence you can define methods on them as well:
def A.method
'class method'
end
A.method #=> 'class_method'
However it is much easier and more convinient to define it within the class body - because of self, which always returns the class itself:
class A
def self.foo
:foo
end
end
self returns A, so this can be read as:
class A
def A.foo
:foo
end
end
The good thing about this is that if you decide to change class name, you only need to do it on top, next to class - self will take care of the rest.
Within the method self is always the receiver of the method. So:
o = Object.new
def o.method
self
end
o.method == o #=> true
It might be however pretty confusing from time to time. Common confusion come from the code:
class A
def get_class
self.class
end
end
class B < A
end
b = B.new
b.get_class #=> B
even though get_class is defined on class A, self refers to the receiver of a method, not the method owner. Hence it evaluates to:
b.class #=> B
For the same reason self within class methods always points to the class the method is executed on.

how rails delegate method works?

After reading the answer by jvans below and looking at the source code a few more time I get it now :). And in case anyone is still wondering how exactly rails delegates works. All rails is doing is creating a new method with (module_eval) in the file/class that you ran the delegate method from.
So for example:
class A
delegate :hello, :to => :b
end
class B
def hello
p hello
end
end
At the point when delegate is called rails will create a hello method with (*args, &block) in class A (technically in the file that class A is written in) and in that method all rails do is uses the ":to" value(which should be an object or a Class that is already defined within the class A) and assign it to a local variable _, then just calls the method on that object or Class passing in the params.
So in order for delegate to work without raising an exception... with our previous example. An instance of A must already have a instance variable referencing to an instance of class B.
class A
attr_accessor :b
def b
#b ||= B.new
end
delegate :hello, :to => :b
end
class B
def hello
p hello
end
end
This is not a question on "how to use the delegate method in rails", which I already know. I'm wondering how exactly "delegate" delegates methods :D. In Rails 4 source code delegate is defined in the core Ruby Module class, which makes it available as a class method in all rails app.
Actually my first question would be how is Ruby's Module class included? I mean every Ruby class has ancestors of > Object > Kernel > BasicObject and any module in ruby has the same ancestors. So how exactly how does ruby add methods to all ruby class/modules when someone reopens the Module class?
My second question is.. I understand that the delegate method in rails uses module_eval do the actual delegation but I don't really understand how module_eval works.
def delegate(*methods)
options = methods.pop
unless options.is_a?(Hash) && to = options[:to]
raise ArgumentError, 'Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, to: :greeter).'
end
prefix, allow_nil = options.values_at(:prefix, :allow_nil)
if prefix == true && to =~ /^[^a-z_]/
raise ArgumentError, 'Can only automatically set the delegation prefix when delegating to a method.'
end
method_prefix = \
if prefix
"#{prefix == true ? to : prefix}_"
else
''
end
file, line = caller.first.split(':', 2)
line = line.to_i
to = to.to_s
to = 'self.class' if to == 'class'
methods.each do |method|
# Attribute writer methods only accept one argument. Makes sure []=
# methods still accept two arguments.
definition = (method =~ /[^\]]=$/) ? 'arg' : '*args, &block'
# The following generated methods call the target exactly once, storing
# the returned value in a dummy variable.
#
# Reason is twofold: On one hand doing less calls is in general better.
# On the other hand it could be that the target has side-effects,
# whereas conceptually, from the user point of view, the delegator should
# be doing one call.
if allow_nil
module_eval(<<-EOS, file, line - 3)
def #{method_prefix}#{method}(#{definition}) # def customer_name(*args, &block)
_ = #{to} # _ = client
if !_.nil? || nil.respond_to?(:#{method}) # if !_.nil? || nil.respond_to?(:name)
_.#{method}(#{definition}) # _.name(*args, &block)
end # end
end # end
EOS
else
exception = %(raise DelegationError, "#{self}##{method_prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}")
module_eval(<<-EOS, file, line - 2)
def #{method_prefix}#{method}(#{definition}) # def customer_name(*args, &block)
_ = #{to} # _ = client
_.#{method}(#{definition}) # _.name(*args, &block)
rescue NoMethodError => e # rescue NoMethodError => e
if _.nil? && e.name == :#{method} # if _.nil? && e.name == :name
#{exception} # # add helpful message to the exception
else # else
raise # raise
end # end
end # end
EOS
end
end
end
Ruby isn't reopening the module class here. In ruby the class Module and the class Class are almost identical.
Class.instance_methods - Module.instance_methods #=> [:allocate, :new, :superclass]
The main difference is that you can't 'new' a module.
Module's are ruby's version of multiple inheritance so when you do:
module A
end
module B
end
class C
include A
include B
end
behind the scenes ruby is actually creating something called an anonymous class. so the above is actually equivalent to:
class A
end
class B < A
end
class C < B
end
module_eval here is a little deceptive. Nothing from the code you're looking at is dealing with modules. class_eval and module_eval are the same thing and they just reopen the class that they're called on so if you want to add methods to a class C you can do:
C.class_eval do
def my_new_method
end
end
or
C.module_eval do
def my_new_method
end
end
both of which are equivalent to manually reopening the class and defining the method
class C
end
class C
def my_new_method
end
end
so when they're calling module_eval in the source above, they're just reopening the current class it's being called it and dynamically defining the methods that you're delegating
I think this will answer your question better:
Class.ancestors #=> [Module, Object, PP::ObjectMixin, Kernel, BasicObject]
since everything in ruby is a class, the method lookup chain will go through all of these objects until it finds what it's looking for. By reoping module you add behavior to everything. The ancestor chain here is a little deceptive, since BasicObject.class #=> Class and Module is in Class's lookup hierarchy, even BasicObject inherits behavior from repening module. The advantage of reopening Module here over Class is that you can now call this method from within a module as well as within a class! Very cool, learned something here myself.
After reading the answer by jvans below and looking at the source code a few more time I get it now :). And in case anyone is still wondering how exactly rails delegates works. All rails is doing is creating a new method with (module_eval) in the file/class that you ran the delegate method from.
So for example:
class A
delegate :hello, :to => :b
end
class B
def hello
p hello
end
end
At the point when delegate is called rails will create a hello method with (*args, &block) in class A (technically in the file that class A is written in) and in that method all rails do is uses the ":to" value(which should be an object or a Class that is already defined within the class A) and assign it to a local variable _, then just calls the method on that object or Class passing in the params.
So in order for delegate to work without raising an exception... with our previous example. An instance of A must already have a instance variable referencing to an instance of class B.
class A
attr_accessor :b
def b
#b ||= B.new
end
delegate :hello, :to => :b
end
class B
def hello
p hello
end
end

How can a nested class access a method in the outer class in Ruby?

def class A
def a
raise "hi" #can't be reached
end
class B
def b
a() #doesn't find method a.
end
end
end
I want to invoke a from b and raise the exception. How can I?
Ruby doesn't have nested classes.
The only way to inherit behavior is, well, via inheritance.
If you want your code to work, you need to use a language which supports nested classes. While this is an incredibly neat and powerful feature, I unfortunately know of only two languages that have nested classes:
BETA, the language which introduced nested classes (and its successor gbeta)
Newspeak
I don't know of any other.
Java has a construct called nested classes, but they have some unfortunate design limitations.
In your example above, it's not the class B that is nested inside A, it is the constant B that is nested inside A. Think about this:
C = A::B
Now, the class is available under two names: A::B and C. It should be immediately obvious that C is global and not nested inside A. (Well, actually, C is nested inside Object, because there aren't really global constants either, but that's beside the point.) But since C and A::B are the same class, it obviously cannot be both nested and not nested. The only logical conclusion is that the class itself isn't nested.
The defining feature of nested classes is that method lookup goes along two dimensions: up the inheritance chain, and outwards through the nesting. Ruby, like 99.9% of all OO languages, only supports the former. (In some sense, nested classes inherit not only the features of their superclass, but also the features of their surrounding class.)
This is just for the lulz:
class A
def a
puts "hello from a"
end
class B
def b
Module.nesting[1].new.a()
end
end
end
I typically do something like this:
class A
def a
puts "hi"
end
def createB
B.new self
end
class B
def initialize(parent)
#parent=parent
end
def b
#parent.a
end
end
end
A.new.createB.b
If you want then nested class to extend the outer class, then do so:
class Outer
class Inner < Outer
def use_outer_method
outer_method("hi mom!")
end
end
def outer_method(foo)
puts foo
end
end
foo = Outer::Inner.new
foo.use_outer_method #<= "hi mom"
foo.outer_method("hi dad!") #<= "hi dad"
Well depending on your circumstances there is actually a solution, a pretty easy one at that. Ruby allows the catching of method calls that aren't captured by the object. So for your example you could do:
def class A
def a
raise "hi" #can't be reached
end
class B
def initialize()
#parent = A.new
end
def b
a() #does find method a.
end
def method_missing(*args)
if #parent.respond_to?(method)
#parent.send(*args)
else
super
end
end
end
end
So then if you do this:
A::B.new().b
you get:
!! #<RuntimeError: hi>
It is probably an easier way to make something like a SubController that only handles certain activities, but can easily call basic controller methods (You would want to send in the parent controller as an argument in the initializer though).
Obviously this should be used sparingly, and it can really get confusing if you use it all over the place, but it can be really great to simplify your code.
You can use methods like module_parent, module_parent_name, module_parents from ActiveSupport to get outer modules, eg.:
class A
def self.a; puts 'a!' end
class B
def self.b; module_parent.a end # use `parent` if rails < 6.0
end
end
A::B.b #=> a!
Was a supposed to be a class method for class A?
class A
def self.a
raise "hi"
end
class B
def b
A::a
end
end
end
A::B.new.b
If you want to keep it as an instance method, you'll obviously have call to it on an instance, like for example A.new.a.

Why does including this module not override a dynamically-generated method?

I'm trying to override a dynamically-generated method by including a module.
In the example below, a Ripple association adds a rows= method to Table. I want to call that method, but also do some additional stuff afterwards.
I created a module to override the method, thinking that the module's row= would be able to call super to use the existing method.
class Table
# Ripple association - creates rows= method
many :rows, :class_name => Table::Row
# Hacky first attempt to use the dynamically-created
# method and also do additional stuff - I would actually
# move this code elsewhere if it worked
module RowNormalizer
def rows=(*args)
rows = super
rows.map!(&:normalize_prior_year)
end
end
include RowNormalizer
end
However, my new rows= is never called, as evidenced by the fact that if I raise an exception inside it, nothing happens.
I know the module is getting included, because if I put this in it, my exception gets raised.
included do
raise 'I got included, woo!'
end
Also, if instead of rows=, the module defines somethingelse=, that method is callable.
Why isn't my module method overriding the dynamically-generated one?
Let's do an experiment:
class A; def x; 'hi' end end
module B; def x; super + ' john' end end
A.class_eval { include B }
A.new.x
=> "hi" # oops
Why is that? The answer is simple:
A.ancestors
=> [A, B, Object, Kernel, BasicObject]
B is before A in the ancestors chain (you can think of this as B being inside A). Therefore A.x always takes priority over B.x.
However, this can be worked around:
class A
def x
'hi'
end
end
module B
# Define a method with a different name
def x_after
x_before + ' john'
end
# And set up aliases on the inclusion :)
# We can use `alias new_name old_name`
def self.included(klass)
klass.class_eval {
alias :x_before :x
alias :x :x_after
}
end
end
A.class_eval { include B }
A.new.x #=> "hi john"
With ActiveSupport (and therefore Rails) you have this pattern implemented as alias_method_chain(target, feature) http://apidock.com/rails/Module/alias_method_chain:
module B
def self.included(base)
base.alias_method_chain :x, :feature
end
def x_with_feature
x_without_feature + " John"
end
end
Update Ruby 2 comes with Module#prepend, which does override the methods of A, making this alias hack unnecessary for most use cases.
Why isn't my module method overriding the dynamically-generated one?
Because that's not how inheritance works. Methods defined in a class override the ones inherited from other classes/modules, not the other way around.
In Ruby 2.0, there's Module#prepend, which works just like Module#include, except it inserts the module as a subclass instead of a superclass in the inheritance chain.
If you extend the instance of the class, you will can do it.
class A
def initialize
extend(B)
end
def hi
'hi'
end
end
module B
def hi
super[0,1] + 'ello'
end
end
obj = A.new
obj.hi #=> 'hello'

Resources