zotherstupidguy
zotherstupidguy

Reputation: 3024

Ruby 2.0 How do I uninclude a module out from a module after including it?

module X
end

module Y
end

module Z
  #TODO include X replacement of including Y
  #TODO include Y replacement of including X
end

Is there a way to work around the fact that ruby contains no uninclude keyword??

Upvotes: 11

Views: 4120

Answers (4)

David Bodow
David Bodow

Reputation: 717

If you want to make a class that can dynamically choose whether or not to include a module, you can achieve that by including the module on the singleton class during initialization.

That won't get you the same thing as "unincluding" the module on one object's singleton class while keeping included on the class itself (which is what comes to mind for me with uninclude), but it may match some features of the refinement solution above (that has the same issue) with a different pattern if that sparks some ideas for you.

module A
  def hi; :hi; end
end

class Foo
  def initialize(include_a = true)
    singleton_class.include(A) if include_a
  end
end

Foo.new.hi
# => :hi

Foo.new(false).hi
# NoMethodError: undefined method `hi' for #<Foo:0x00007fe19a973f00>

Understand that this is an old question, but if you're looking around for uninclude functionality, it's worth really thinking about what precisely you're trying to do with it - is something like "dynamic inclusion" enough?

Upvotes: 0

Cary Swoveland
Cary Swoveland

Reputation: 110685

I'm not too happy with this, but it does work if both modules contain the same method names.

file c.rb

module A
  def me
    puts "I am C"
  end
  def whosit?
    puts "It's me, Becky"
  end
end

file d.rb

module A
  def me
    puts "I am D"
  end
end

Then

class X
  load('c.rb')
  include A
end

x = X.new

x.me # => I am C
x.whosit? # => It's me, Becky
load('d.rb')
x.me # => I am D
x.whosit? # => It's me, Becky !! Unwanted !!
load('c.rb')
x.me # => I am C

load() is just opening module A and changing and/or adding code; anything there that it does not touch remains. load() is not real bright. I think it basically does an eval() and could care less if it loads the same file more than once.

To use this, do not also require c.rb or d.rb.

Edit: In an earlier edit I added an observation about require_relative. On reflection, I see it was neither relevant nor interesting, so off with its head.

Upvotes: 0

Boris Stitnicky
Boris Stitnicky

Reputation: 12578

The genuine answer is that in Ruby, be it 1.x or 2.x, there is no way to uninclude a module once included. But I know that someone, somewhere has written Ruby extension that allows unincluding modules.

EDIT: OK, actually, OP is the duplicate of What is the opposite of Ruby's include?, so according to its answer by @eliah and banister the libraries in question are https://github.com/yrashk/rbmodexcl and https://github.com/banister/mixology19

Upvotes: 1

davogones
davogones

Reputation: 7399

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

Upvotes: 8

Related Questions