How to discover the overrided methods in Ruby/Rails? - ruby-on-rails

Hey guys.
How do I know the methods that a child class overrided in my super class?
I have this:
class Test
def self.inherited(child)
# child.overrided_methods???
end
def self.foo
end
def self.bar
end
end
def Child < Test
def self.bar
puts "bar"
end
end
The method self.inherited is called when a subclass of Test is loaded. So I get the reference to this subclass in child, but I don't know how to get the methods that were overrided by this subclass.
Any ideas?
--
Arsen suggested the use of self.method_added(name) instead of self.inherited(child), but this method catches only instance methods and I want to catch class methods. Does anyone know another methods that does the same thing but with class methods?
In the last case I'll consider using a singleton and convert all this class methods to instance methods then the problem is solved.

For instance methods there is an Object::method_added(name) method you can override, similar to 'inherited' you have used:
class test
def self.method_added(name)
puts "method_added(#{name.inspect})"
super
end
end
irb(main):002:0> class Child < Test; def foo; end; end
method_added(:foo)
=> nil
You can then compare a received name to a list of your methods:
Test.instance_methods.include?(name.to_s)
With class methods this approach does not work (even if you do things like class << self magic), but a helpful fellow knew the answer: http://www.ruby-forum.com/topic/120416 :
class Test
def self.singleton_method_added(name)
puts "Class method added #{name.inspect}"
end
end
This is only the first part of the problem, because you need to know which class defined the method (it will be self) and whether the method is a new one, or overridden one. Experiment with this code:
class Test
def self.singleton_method_added(name)
if self == Test
puts "My own class method added: #{self.name}.#{name.inspect}"
elsif Test.methods(false).include?(name.to_s)
puts "Class method overriden: #{self.name}.#{name.inspect}"
elsif Test.methods(true).include?(name.to_s)
puts "My parent's class method overriden: #{self.name}.#{name.inspect}"
else
puts "New class method added: #{self.name}.#{name.inspect}"
end
end
end

Maybe a first step to the solution:
By calling child.instance_method(:bar) (if child refers to the class) or child.method(:bar) (if it refers to an instance of Child) you can get an UnboundMethod or Method object representing your method:
a = Test.instance_method(:foo)
b = Child.instance_method(:foo)
Unfortunately, a == b evaluates to false, although both refer to the same method.

def overridden_methods
klass = self.class
klass.instance_methods.select {|m| klass.instance_method(m).owner == klass}
end
Change according to your needs.

Related

ruby monkey patching on the fly

Is there a way to implement monkey patching while an object is being instantiated?
When I call:
a = Foo.new
Prior to the instance being instantiated, I would like to extend the Foo class based on information which I will read from a data store. As such, each time I call Foo.new, the extension(s) that will be added to that instance of the class would change dynamically.
tl;dr: Adding methods to an instance is possible.
Answer: Adding methods to an instance is not possible. Instances in Ruby don't have methods. But each instance can have a singleton class, where one can add methods, which will then be only available on the single instance that this singleton class is made for.
class Foo
end
foo = Foo.new
def foo.bark
puts "Woof"
end
foo.bark
class << foo
def chew
puts "Crunch"
end
end
foo.chew
foo.define_singleton_method(:mark) do
puts "Widdle"
end
foo.mark
are just some of the ways to define a singleton method for an object.
module Happy
def cheer
puts "Wag"
end
end
foo.extend(Happy)
foo.cheer
This takes another approach, it will insert the module between the singleton class and the real class in the inheritance chain. This way, too, the module is available to the instance, but not on the whole class.
Sure you can!
method_name_only_known_at_runtime = 'hello'
string_only_known_at_runtime = 'Hello World!'
test = Object.new
test.define_singleton_method(method_name_only_known_at_runtime) do
puts(string_only_known_at_runtime)
end
test.hello
#> Hello World!
Prior to the instance being instantiated, I would like to extend
Given a class Foo which does something within its initialize method:
class Foo
attr_accessor :name
def initialize(name)
self.name = name
end
end
And a module FooExtension which wants to alter that behavior:
module FooExtension
def name=(value)
#name = value.reverse.upcase
end
end
You could patch it via prepend:
module FooPatcher
def initialize(*)
extend(FooExtension) if $do_extend # replace with actual logic
super
end
end
Foo.prepend(FooPatcher)
Or you could extend even before calling initialize by providing your own new class method:
class Foo
def self.new(*args)
obj = allocate
obj.extend(FooExtension) if $do_extend # replace with actual logic
obj.send(:initialize, *args)
obj
end
end
Both variants produce the same result:
$do_extend = false
Foo.new('hello')
#=> #<Foo:0x00007ff66582b640 #name="hello">
$do_extend = true
Foo.new('hello')
#=> #<Foo:0x00007ff66582b280 #name="OLLEH">

No method error for class variable defined with attr_accessor

I want to define methods dynamically using an array of strings.
Here is a simple piece of code that should achieve that.
class SomeClass
attr_accessor :my_array
def initialize(user, record)
#my_array=[]
end
my_array.each do |element|
alias_method "#{element}?".to_sym, :awesome_method
end
def awesome_method
puts 'awesome'
end
end
When I instantiate this class in the console, I get the following error
NoMethodError (undefined method `each' for nil:NilClass)
What is wrong with this code and how to make it work. any help highly appreciated :)
Edit 1:
What I ultimately want to achieve is to inherit from SomeClass and override my_array in the child class to dynamically define methods with its attributes like so
class OtherClass < SomeClass
my_array = %w[method1 method2 method3]
# Some mechanism to over write my_array.
end
And then use self.inherited to dynamically define methods in child class.
Is there a good way to achieve this?
In your code, you use an instance variable (#my_array) and an attr_accessor over it, and then try to access my_array from class level (that is, from the body of the class definition, outside of any methods). But instance variables only exist at instance level, so it is not available in the class scope.
One solution (the natural one, and the one which you would probably use in other languages) is to use a class variable: ##my_array. But class variables in ruby are a little problematic, so the best solution would be to make use of class instance variables, like that:
class SomeClass
class << self
attr_accessor :my_array
end
#my_array=[]
def initialize(user, record)
end
#my_array.each do |element|
alias_method "#{element}?".to_sym, :awesome_method
end
def awesome_method
puts 'awesome'
end
end
The syntax is a little tricky, so, if you look that up and it still doesn't makes sense, try just reading about scopes and using a regular class variable with ##.
Edit:
Ok, so, after your edit, it became more clear what you are trying to accomplish. A full working example is like follows:
class SomeClass
class << self
attr_accessor :my_array
end
#my_array=[]
def awesome_method
puts 'awesome'
end
def self.build!
#my_array.each do |element|
self.define_method("#{element}?".to_sym){ awesome_method }
end
end
end
class ChildClass < SomeClass
#my_array = %w[test little_test]
self.build!
end
child_instance = ChildClass.new
child_instance.test?
>> awesome
child_instance.little_test?
>> awesome
So, I've made some tweaks on SomeClass:
It does not need an initialize method
I tried to use the inherited hook for this problem. It won't ever work, because this hook is called as soon as "ChildClass < SomeClass" is written, and this must be before you can define something like #my_array = %w[test little_test]. So, I have added a self.build! method that must be called in the child instances so that they build their methods from my_array. This is inevitable, but I think it is also good, because it makes more explicit in the subclasses that you are doing something interesting there.
I think you want "define_method", not "alias_method".
awesome_method in passed in a block, which is ruby's way of doing functional programming.
With that done, ChildClass inherits from SomeClass, and it's instances have the dynamically created methods 'test?' and 'little_test?'.
You need to change my_array to class level accessible, in my case class constant.
class SomeClass
DYNAMIC_METHOD_NAMES = %w(method_a method_b method_C).freeze
def initialize(user, record)
end
DYNAMIC_METHOD_NAMES.each do |element|
alias_method "#{element}?".to_sym, :awesome_method
end
def awesome_method
puts 'awesome'
end
end

Calling method within Class

im new in ruby so this code is not working, please provide me the proper way of calling a method within class
Class TestClass
def testMethod
puts "hello"
end
testMethod
end
UPDATE
hi everyone thanks for all the help and comments just like #Stefan and #Matt said, my example is very uncommon to use this way and thanks for giving the right path anyway i just want to add this from my question and i found a way to work
class TestClass
def self.testMethod
puts "hello"
end
TestClass.testMethod
end
class TestClass
# a class method
def self.test_method
puts "Hello from TestClass"
end
# an instance method
def test_method
puts "Hello from an instance of TestClass"
end
end
# call the class method
TestClass.test_method
# create and instance object of TestClass
instance_of_TestClass = TestClass.new
# call the instance method of the new object
instance_of_TestClass.test_method
Your example defines a class with an instance method. You then try to call the instance method from the class - this won't work.
Instead, you need to call the method as in instance, or convert it to a class method.
class TestClass
def self.testMethod
puts "hello"
end
testMethod
end
Instance and class level distinction is a fundamental concept, you would benefit from taking some tutorials, start with a read of http://www.railstips.org/blog/archives/2009/05/11/class-and-instance-methods-in-ruby/
You have to call method in with in class like:
class TestClass
def testMethod
puts "hello"
end
def test_2
testMethod
end
end
object = TestClass.new()
puts object.test_2

Access a subclass' instance method from a superclass object

I have a class that inherits from another class. The setup of the superclass is as follows:
class Creator::BaseResource < Creator::Base
def request_attributes(action = :create)
"super"
end
end
And the subclass:
class Creator::Resource::HypervisorGroup < Creator::BaseResource
def request_attributes(action = :create)
"sub"
end
end
Now, if I have an instance of "Creator::BaseResource", and there is a DB column named "resource_class" which contains "Resource::HypervisorGroup" that makes it known that its a subclass, I would like to be able to say object.request_attributes and get "super" returned, in this example.
The code is far more complicated than this, obviously, but that's the gist of what I want to accomplish. Is it possible? Thank you.
What about that :
class Creator::Resource::HypervisorGroup < Creator::BaseResource
def request_attributes(action = :create, use_super=false)
super and return if use_super
"sub"
end
end
And then, you can call object.request_attributes(:create, true) to get the superclass method called

Not understanding Classes, Modules, and the class << self method

I have the following code:
class MyClass
module MyModule
class << self
attr_accessor :first_name
def myfunction
MyModule.first_name = "Nathan"
end
end
end
end
When I call the method myfunction like so, it works fine:
> me = MyClass::MyModule.myfunction
=> "Nathan"
> me
=> "Nathan"
But if I removed the class << self and add a self. prefix to myfunction, it doesn't work.
For example:
class MyClass
module MyModule
attr_accessor :first_name
def self.myfunction
MyModule.first_name = "Nathan"
end
end
end
> me = MyClass::MyModule.myfunction
NoMethodError: undefined method `first_name=' for MyClass::MyModule:Module
I'm trying to understand the class << self method. I thought it was a way add the self. prefix to the all the methods inside of it, but if that was true, why doesn't it work if I remove it and prefix each method with self. manually?
Thanks in advance for your help.
This is because your attr_accessor :first_name is also wrapped by the class << self.
To do it the way you suggest, you can use mattr_accessor like so:
require 'active_support'
class MyClass
module MyModule
mattr_accessor :first_name
def self.myfunction
MyModule.first_name = "Nathan"
end
end
end
To better understand how you can achieve what you want, take a look at the following example:
module PrintingModule
def self.included(object)
object.extend(ClassMethods)
end
module ClassMethods
def class_method_of_class
puts "I am class #{self.name}"
end
end
def instance_method_of_class
puts "My name is: #{#name}"
end
class << self
def static_module_method
puts "Printer version 1.0"
end
end
end
class SomeObject
include PrintingModule
def initialize(name)
#name = name
end
end
object = SomeObject.new("Something")
object.instance_method_of_class
SomeObject.class_method_of_class
PrintingModule.static_module_method
I hope it's more clear now, note that this is just one of possible way (there are others)
UPDATE:
I'll try to be more specific. When you define instance/singleton methods on module, what you are really doing is that you are defining instance methods of class which will include that module and on the other hand, class methods defined on module will become class methods of that module. The second think to know is that attr_accessor creates instance method for getter and setter of the given parameter.
Now to answer one part of your question, in the first example you are creating 3 class methods on module's class. In the second one, you are creating 1 class method where you are trying to access another class method (setter), but your getters and setters are defined as instance methods = they will become instance of method of class which will include your module, you cannot get to them this way = you have no access to your getters and setters.
As for explanation of self, well I'm not that skilled, but as far as I know, when you use "class << self" you are opening eigenclass (each object has it's own anynonymous one) of the object (note that Class, modules or instances of classes are of course objects too) where you are defining instance methods. Class method of object in Ruby = instance method of the eigenclass of the object. So you can do this for example:
text = "something"
class << text
def say_hi
puts "Hi!"
end
end
text.say_hi
When you create instance of class (String in that example), that instance gets it's own unique anonymous class which is subclass of that Class. In the example, you have defined instance method on the eigenclass of the anonymous subclass of String class. So you can use method "say_hi" on the text object but not on the String class. So "class << self" is opening those eigenclasses.
On the other hand, "self" alone just represents an object in the current context, which means the same in some scenarios (for example yours). As for self.included method, it is just a callback method which gets called when the module is included in the class with a parameter representing the object (here class SomeObject).
I hope that I have answered at least part of your question.
More information here:
Difference between 'self.method_name' and 'class << self' in Ruby

Resources