Ruby 2.0 How do I uninclude a module out from a module after including it?
If you really need this kind of functionality, you could probably do it by using refinements.
class Foo
end
module X
def x
puts 'x'
end
end
module Y
end
module R
refine Foo do
include X
include Y
end
end
# In a separate file or class
using R
# Foo now includes X and Y
Foo.new.x
# In a different file or class
# Foo no longer includes X and Y
Foo.new.x # NoMethodError
Redefining class in Ruby seems to include wrong module
I think what you may be missing is that the second class A ... end
is not redefining the class, it's adding to it. You’re allowed to "open" a class multiple times in ruby and (re-)define whatever you want. That, and what you seem to have already figured out, which is that include
more or less just drops the code from the module into that spot in the class definition, unless that module has already been included in which case it does nothing.
You can do this with any class at all (whether advisable or not)
class Hash
def to_a
'lol you probably wanted an array here'
end
end
{foo: :bar}.to_a # Returns above string instead of [:foo, :bar]
Overriding instance methods of a class by mixing in a module
You could remove each of B
's methods from A
before including B
.
class A
def method1
"A\#method1"
end
def method2
"A\#method2"
end
B.instance_methods(false).each { |method|
remove_method(method) if instance_methods(false).include?(method)
}
include B
end
Or from within B
:
module B
def method1
"B\#method1"
end
def method2
"B\#method2"
end
def self.append_features(mod)
instance_methods(false).each { |method|
mod.send(:remove_method, method) if mod.instance_methods(false).include?(method)
}
super
end
end
How do I access an instance variable from a module that was included dynamically?
Here is a meta programming for you :
#!/usr/bin/env ruby
class Foo
attr_accessor :current_session
def initialize(current_session)
@current_session = current_session
end
def foobarbaz
session = current_session
Bar.module_eval { @current_session = session }
Baz.send(:include, Bar)
end
end
module_eval
says
Evaluates the string or block in the context of mod, except that when a block is given, constant/class variable lookup is not affected....
Thus inside Bar.module_eval { @current_session = session }
, @current_session
is the instance variable of Bar
only and I am setting the value of it to the instance variable value of the class Foo
, which is @current_session
.
Baz.send(:include, Bar)
is helpfull, which returns class/module itself, which is including the other module. include(module, ...) → self
.
class Baz
end
Read this post to understand the below stuff.
module Bar
class << self
attr_reader :current_session
end
def foobar
Bar.current_session
end
end
puts Foo.new('current_session').foobarbaz.new.foobar
# >> current_session
Update
As @Christian Fazzin gave a good suggestion :-
If you want Bar
module to have write method also, then you have to do 2 changes -
Bar
should contain thenattr_accesor :current_session
, instead of what it has now.- You don't need to use the power of
module_eval
there, rather use syntactic sugraness of write methods, like putBar.current_session = current_session
inside the methodfoobarbaz
. Remove the linessession = current_session
andBar.module_eval { @current_session = session }
.
How do you find all modules and classes within a module, recursively?
class Module
def all_the_modules
[self] + constants.map {|const| const_get(const) }
.select {|const| const.is_a? Module }
.flat_map {|const| const.all_the_modules }
end
end
A.all_the_modules
# => [A, A::Aa, A::Aa::B]
This code will break if you do have circular namespaces, akaA::Aa::B.const_set(:A, A)
.
prepend module with ActiveSupport::Concern ? ruby 2+
prepend
with ActiveSupport::Concern
(Rails 6.1+)
Rails 6.1 added support of prepend
with ActiveSupport::Concern
.
Please, see the following example:
module Imposter
extend ActiveSupport::Concern
# Same as `included`, except only run when prepended.
prepended do
end
end
class Person
prepend Imposter
end
It is also worth to mention that concerning
is also updated:
class Person
concerning :Imposter, prepend: true do
end
end
Sources:
A link to the corresponding commit.
Rails allows a module with extend ActiveSupport::Concern to be prepended.
prepend and concerning docs.
Modifying devise modules after first generation
Change the lines you want in the migration file, then redo the migration as per these instructions:
http://guides.rubyonrails.org/migrations.html
Overriding instance methods of a class by mixing in a module
You could remove each of B
's methods from A
before including B
.
class A
def method1
"A\#method1"
end
def method2
"A\#method2"
end
B.instance_methods(false).each { |method|
remove_method(method) if instance_methods(false).include?(method)
}
include B
end
Or from within B
:
module B
def method1
"B\#method1"
end
def method2
"B\#method2"
end
def self.append_features(mod)
instance_methods(false).each { |method|
mod.send(:remove_method, method) if mod.instance_methods(false).include?(method)
}
super
end
end
Related Topics
Can't Get Rack-Cors Working in Rails Application
How to Run Rails Console in the Test Environment and Load Test_Helper.Rb
Is There a Less Intrusive Alternative to Rspec's 'Should_Receive'
Rails Search with Optional Parameters
Creating Routes with an Optional Path Prefix
Best Ruby Idiom for "Nil or Zero"
Hashes of Hashes Idiom in Ruby
Ruby on Rails: Devise, Want to Add Invite Code
Rspec: How to Test If a Method Was Called
Cannot Execute "Rails Console" Due to an Error with Readline
How to Handle Errors with Httparty
Ruby Dropped in Netbeans 7,How to Use It in Netbeans7
How to Convert a String to a Class Method
Rails Erb Form Helper Options_For_Select :Selected