I'll explain what i'm looking for in code as thats probably the most succinct:
module Mixin
def method
puts "Foo"
end
end
class Whatever
include Mixin
end
w = Whatever.new
w.method
=> "Foo"
# some magic here
w2 = Whatever.new
w.method
=> NoMethodError
I had tried just undefining the Mixin module using remove_const, but this doesn't seem to make any difference to Whatever. I had assumed that #include just added a reference to the module into the class's method resolution chain - but this behaviour doesn't agree with that.
Can anyone tell me what include actually does behind the scenes, and how to reverse this?
As it seems probably you want to accomplish these on instances instead of the whole class, so I would change klochner's code a bit to handle just one instance instead of all the instances of a class.
module ModuleRemover
def remove_module(mod, options = {})
metaclass = class << self; self end
mod.instance_methods.each {|method_name| metaclass.class_eval { undef_method(method_name.to_sym) }}
end
end
As Mladen pointed out, it would be cool to avoid removing methods that are overwritten on the host class, so an [only, exclude] options for this method would be ideal.
>> c1 = C.new
>> c1.foo
=> fooing
>> c1.extend(ModuleRemover)
>> c1.remove_module(Mod)
>> c1.foo
=> NoMethodError: undefined method `foo' for #< C:0x11b0d90>
>> c2 = C.new
>> c2.foo
=> fooing
module Mod
def foo
puts "fooing"
end
end
class C
include Mod
def self.remove_module(m)
m.instance_methods.each{|m| undef_method(m)}
end
end
>> c = C.new
>> c.foo
fooing
>> C.remove_module(Mod)
=> ["foo"]
>> c.foo
NoMethodError: undefined method `foo' for #< C:0x11b0d90>
I'm not sure what you're trying to accomplish, but perhaps instead of using include to add instance methods, what you want to do is use extend to add methods just to particular instances of the class, then you wouldn't need to remove them.
More information on the difference between include and extend
Some years ago I used the gem evil for un-including modules etc., but apparently it is no longer maintained. So I just tried un instead (only on my old ruby 1.8.7). Worked fine as advertised:
DESCRIPTION:
un provides unextend and uninclude to allow for a better prototype-oriented programming experience.
If you replace your "# some magic here" (after installing un) by
require 'un'
Whatever.uninclude Mixin
you get the behavior as described by you - almost. Object has already a method called method, so you get a "wrong number of arguments" error instead.
It would be nice if someone tries it on ruby 1.9 or on jruby and reports the results (I make the answer community wiki for this).
Related
module Access
def last
self[-1]
end
def start_end
self[0] + last
end
end
module StringExt
refine String do
include Access
end
end
using StringExt
puts 'abcd'.last # => d
puts 'abcd'.start_end
When a class being refined with too many connected methods, I think it is better to extract them to a module. However, in above example which demos a problem when one method calls another(see the last statement), and it produces following error.
in 'start_end': undefined local variable or method 'last' for "abcd":String (NameError)
Similar issue was solved using a global variable, which also works for my example. But I'm seeking another better way to organize inter-called methods being refined and avoid a global thing.
How would advice a better way to organize those methods?
Here's a general pattern I ended up using. Basically I found no workaround for using global identifiers at some level. But this can be done fairly cleanly by making those globals classes/modules. This will be more clear as an example:
module StringPatches
def self.non_empty?(string)
!string.empty?
end
def non_empty?
StringPatches.non_empty?(self)
end
def non_non_empty?
!StringPatches.non_empty?(self)
end
refine String do
include StringPatches
end
end
class Foo
using StringPatches
puts "asd".non_empty? # => true
puts "asd".non_non_empty? # => false
end
The class methods on StringPatches don't get exported to using. But since classes/modules are constants (globals) they can be accessed from anywhere.
Suppose I've got a section of Ruby code where I'd like to alias a method (I don't know why; let's just suppose I have a good reason).
class String
alias_method :contains?, :include?
end
Would it be possible for me, after this section, to remove this alias?
remove_method should work in most cases. But if your alias_method overwrites an existing method, you may need to save the original via a separate alias_method call.
# assuming :contains? is already a method
alias_method :original_contains?, :contains?
alias_method :contains?, :include?
Then to restore the original state:
alias_method :contains?, :original_contains?
remove_method :original_contains? # optional
Note also that modifying a class that's used in multiple threads is prone to race conditions. And if you're trying to disallow libs from using the alias, you can't prevent that if you're calling those libs' methods while the alias exists. We might see a way to do this in ruby 2.0: http://yehudakatz.com/2010/11/30/ruby-2-0-refinements-in-practice/
It would be helpful if you could say why you want to remove the alias. If the method name did not exist before, no other libs should be affected by your monkey-patch. Also, you should consider subclassing String (or delegating to a string instance) rather than patching String.
def hello
puts "Hello World"
end
alias :hi :hello
hi #=> "Hello World"
undef hi
hi #=> NameError
hello #=> "Hello World"
EDIT: Note that this will only work on methods created on the main object. In order to enact this on a class, you'd need to do something like , Hello.class_eval("undef hi")
However, from a metaprogramming standpoint, when dealing with classes, I like the usage of remove_method :hi since it'll cause the method lookup to fall down and grab the method from a parent class.
class Nums < Array
def include?
puts "Just Kidding"
end
end
n = Nums.new
n << 4 #=> [4]
n.include? #=> "Just kidding"
Nums.class_eval("remove_method :include?")
n.include? 4 #=> true
Number.class_eval("undef include?")
n.include? 4 #=> NoMethodError
remove_method is much more meta friendly.
Documentation I've read tells me to use Module.method to access methods in a module. However, I can use Module::method as well. Is this syntactic sugar, or am I confused?
module Cat
FURRY_LEVEL = 4
def self.sound
%w{meow purr hiss zzzz}.sample
end
end
puts Cat.sound # This works.
puts Cat::sound # This also works. Why?!
puts Cat.FURRY_LEVEL # Expected error occurs here.
puts Cat::FURRY_LEVEL # This works.
Constant resolution always requires that you use ::.
Method invocation is idiomatically and usually a period (.), but :: is also legal. This is not just true for so-called module methods, but for invoking any method on any object:
class Foo
def bar
puts "hi"
end
end
Foo.new::bar
#=> hi
It's not so much "syntax sugar" as it is simply alternative syntax, such as the ability to write if or case statements with either a newline, then and newline, or just then.
It is specifically allowed because Ruby allows methods with the same name as a constant, and sometimes it makes sense to think that they are the same item:
class Foo
class Bar
attr_accessor :x
def initialize( x )
self.x = x
end
end
def self.Bar( size )
Foo::Bar.new( size )
end
end
p Foo::Bar #=> Foo::Bar (the class)
p Foo::Bar(42) #=> #<Foo::Bar:0x2d54fc0 #x=42> (instance result from method call)
You see this commonly in Ruby in the Nokogiri library, which has (for example) the Nokogiri::XML module as well as the Nokogiri.XML method. When creating an XML document, many people choose to write
#doc = Nokogiri::XML( my_xml )
You see this also in the Sequel library, where you can write either:
class User < Sequel::Model # Simple class inheritance
class User < Sequel::Model(DB[:regular_users]) # Set which table to use
Again, we have a method (Sequel.Model) named the same as a constant (Sequel::Model). The second line could also be written as
class User < Sequel.Model(DB[:regular_users])
…but it doesn't look quite as nice.
The :: is called scope resolution operator, which is used to find out under what scope the method, class or constant is defined.
In the following example, we use :: to access class Base which is defined under module ActiveRecord
ActiveRecord::Base.connection_config
# => {:pool=>5, :timeout=>5000, :database=>"db/development.sqlite3", :adapter=>"sqlite3"}
We use :: to access constants defined in module
> Cat::FURRY_LEVEL
=> 4
> Cat.FURRY_LEVEL
=> undefined method `FURRY_LEVEL' for Cat:Module (NoMethodError)
The . operator is used to call a module method(defined with self.) of a module.
Summary: Even though both :: and . does the same job here, it is used for different purpose. You can read more from here.
I'm doing some metaprogramming in Ruby, and I need to dynamically generate a sibling class inside of a module. In doing so, I want to call const_set on the module, but I don't know which Module constant to call that on until runtime. An example:
Given classes
Foo::Bar::Baz
Foo::Quox::Quack
I want to be able to call a function like this (oversimplified here):
def generate_from klass
mod = klass.enclosing_module # <- THIS LINE is the one I need to figure out
mod.const_set("GeneratedClassName", Class.new)
end
and what I want to end up with, when calling with Baz, is a new class defined as
Foo::Bar::GeneratedClassName
and with a Quack, I want
Foo::Quox::GeneratedClassName
The only way I know of is to split up klass.name, then repeatedly call const_get on those strings, constantized. Does anyone know of a more elegant way?
This should get you on track:
module Foo
module Bar
class Baz
def initialize
#nesting = Module.nesting
end
def enclosing_module
#nesting.last
end
end
end
end
puts Foo::Bar::Baz.new.enclosing_module #=> Foo
Relevant documentation:
http://ruby-doc.org/core/classes/Module.html#M000441
Got it.
ActiveSupport has this Ruby extension, Module#parent. It's good enough for my use.
In Rails you can use a combination of deconstantize and constantize.
'Foo::Bar::Baz'.deconstantize.constantize # => Foo::Bar
so in a method of the class it can be used like this:
self.class.name.deconstantize.constantize
In case anyone is looking for a pure ruby version:
def get_parent_type
#Note: This will break for base types (lacking '::' in the name)
parent_type=self.class.name.split('::')[0...-1]
begin
Object.const_get(parent_type.join('::'))
rescue NameError => e
nil
end
end
I got this question from this discussion. A method call like object.m does not always mean the class of "object" has a "m" method, just like the find method to a Array object is not directly originated from Array object, but from the mixed-in Enumerable module. My question is, given a method, how can we determine the class from which the method originated?
Any class/object method is an object in Ruby, and has some methods of it's own.
So you can do this:
[].method(:count).inspect
=> "#<Method: Array#count>"
[].method(:detect).inspect
=> "#<Method: Array(Enumerable)#detect>"
Quick bit of RegEx and you're done.
tobyhede's answer is awesome, but I just did a bit of digging in irb and there's no need to slice up the output of #inspect. The Method class
>> Object.new.method(:inspect)
=> #<Method: Object(Kernel)#inspect>
has some useful methods of its own:
>> Object.new.method(:inspect).methods - Object.methods
=> ["owner", "call", "to_proc", "unbind", "arity", "receiver", "[]"]
In particular the #owner method, which returns the owner as a proper object:
>> [].method(:count).owner
=> Array
>> [].method(:detect).owner
=> Enumerable
maybe you use caller() to give you the backtrace see:
http://www.ruby-doc.org/core/classes/Kernel.html#M005955
I'm thinking something like this could work
def print_ancestor_definitions(cl,method)
ancestors = cl.ancestors
p ancestors.join(' < ') #Print heirarchy
p "Searching..."
ancestors.each do |c|
if c.instance_methods.include? method
p "#{c} defines #{method} as an instance method!"
elsif c.singleton_methods.include? method
p "#{c} defines #{method} as a singleton method"
else
p "#{c} doesn't define #{method}"
end
end
end
print_ancestor_definitions(Array,'find')
# >> "Array < Enumerable < Object < Kernel"
# >> "Searching..."
# >> "Array defines find as an instance method!"
# >> "Enumerable defines find as an instance method!"
# >> "Object doesn't define find"
# >> "Kernel doesn't define find"
I suppose the last one to have the method is the one who defines it?
I'm not sure we can precisely find where a method come from, when you include a mixin, all the methods become part of your class as if you did put them there. See answer from dylanfm for an approx.