Ruby 2.0 How to Uninclude a Module Out from a Module After Including It

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 then attr_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 put Bar.current_session = current_session inside the method foobarbaz . Remove the lines session = current_session and Bar.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, aka
A::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



Leave a reply



Submit