Ruby: Module, Mixins and Blocks Confusing

Ruby: Module, Mixins and Blocks confusing?

By the way: in Ruby 2.0, there are two features which help you with both your problems.

Module#prepend prepends a mixin to the inheritance chain, so that methods defined in the mixin override methods defined in the module/class it is being mixed into.

Refinements allow lexically scoped monkeypatching.

Here they are in action (you can get a current build of YARV 2.0 via RVM or ruby-build easily):

module Sum
def sum(initial=0)
inject(initial, :+)
end
end

module ArrayWithSum
refine Array do
prepend Sum
end
end

class Foo
using ArrayWithSum

p [1, 2, 3].sum
# 6
end

p [1, 2, 3].sum
# NoMethodError: undefined method `sum' for [1, 2, 3]:Array

using ArrayWithSum
p [1, 2, 3].sum
# 6

idiomatic RSpec testing with mixins and blocks?

First, the operations provided by FileUtils should be tested separately, in a FileUtils test.

Then you should only validate that the block you provide to the UserDataFile is actually used. There are 2 cases - one just yields the instance, while the other uses instance_eval. You need to validate both.

For the first case you can use the yield RSpec matcher. It will look like:

expect { |b| MyModule::UserDataFile.new(client, &b) }.to yield_with_args(kind_of(UserDataFile)) }

The second one is more tricky. You can pass a block and add expectation for something done within a block. A classical example is to throw from the block and expect that symbol to be thrown:

my_proc = proc { throw :my_proc_was_called }

expect { MyModule::UserDataFile.new(client, &my_proc) }.to throw_symbol :my_proc_was_called

As for the reason you get NoMethodError - you are stubbing the add_data on the class, but the code is calling it on the instance. You will have to use allow_any_instance_of to stub the way you are trying to do

To break up Ruby class into separate files by mixins or plain definitions?

Are your support methods general enough that they might be useful for other totally unrelated classes? If so, a mixin is the proper way to do this, since it lets you easily reuse the support code.

However if your support methods are very specific to ReallyBigClass and are unlikely to work if included somewhere else, reopening the class is the way to go. Using a mixin there could give the appearance that the methods are more general than they really are, when really they should only be used with instances of a specific class.

That being said, I think your question indicates a larger design problem. If you are in the former case (general methods), you should be designing more general modules in the first place to avoid tight coupling. A module called ReallyBigClassFileB gives off some strong code smell. In the latter case (very specific methods) if your class is so big that its file is unmanageably large you probably need to refactor something. Maybe your class is responsible for too much? Maybe it could use some subclasses (which make sense in separate files)?

Why does including this module not override a dynamically-generated method?

Let's do an experiment:

class A; def x; 'hi' end end
module B; def x; super + ' john' end end
A.class_eval { include B }

A.new.x
=> "hi" # oops

Why is that? The answer is simple:

A.ancestors
=> [A, B, Object, Kernel, BasicObject]

B is before A in the ancestors chain (you can think of this as B being inside A). Therefore A.x always takes priority over B.x.

However, this can be worked around:

class A
def x
'hi'
end
end

module B
# Define a method with a different name
def x_after
x_before + ' john'
end

# And set up aliases on the inclusion :)
# We can use `alias new_name old_name`
def self.included(klass)
klass.class_eval {
alias :x_before :x
alias :x :x_after
}
end
end

A.class_eval { include B }

A.new.x #=> "hi john"

With ActiveSupport (and therefore Rails) you have this pattern implemented as alias_method_chain(target, feature) http://apidock.com/rails/Module/alias_method_chain:

module B
def self.included(base)
base.alias_method_chain :x, :feature
end

def x_with_feature
x_without_feature + " John"
end
end

Update Ruby 2 comes with Module#prepend, which does override the methods of A, making this alias hack unnecessary for most use cases.

What's the hierarchical relationship between a Module and a Class?

Modules can be used for two things in Ruby: as namespaces for constants and as mixins.

The namespace usage is quite similar to C# namespaces: a module can contain constants (and all constants are contained in modules, even if you don't explicitly see it, in which case they belong to Object) which are namespaced to that module. So, Foo::BAR and Baz::BAR are two different constants even though they have the same name.

Mixins are a bit trickier. One way to look at a mixin, is that a mixin is a class which doesn't know its superclass (or a class that is parameterized by its superclass). Okay, this sounds a bit convoluted. Let's look at an example.

Imagine, something like this were possible in C#:

interface IEachable<E> {
IEachable<E> Each(Action<E> block);
}

class Enumerable<S, E> : S where S : IEachable<E> {
List<T> Map(Func<E, T> block) {
var res = new List<T>();
this.Each(e => {†res.Add(block(e));});
return res;
}
}

So, you have a generic class Enumerable which inherits from its type parameter S (the superclass). This is actually a pretty accurate description of the Enumerable mixin in Ruby. Everytime you instantiate the generic class into a concrete type, it ends with a different superclass.

So, the same class appears multiple times in the inheritance hierarchy, each time with a different superclass, but always just one.

This is different from multiple inheritance, where the same class appears once in the inheritance hierarchy, with multiple superclasses.

This property, that the class always has just one superclass, is called linearization and it solves a lot of the problems that traditional multiple inheritance has, which are usually related to the fact that there are multiple possible paths between two classes in the inheritance DAG, whereas with mixin linearization, there is just an inheritance tree, so there is always just one possible path.

In particular, this is what happens, when you mix a module M into a class C with superclass S:

module M; end

class C < S
include M
end

When you call include, Ruby will

  1. create a new class M' whose method table pointer, constant table pointer, class variable table pointer and instance variable table pointer point to M's method table, constant table, class variable table and instance variable table
  2. set M''s superclass to C's current superclass (i.e. S)
  3. set C's superclass to M'

So that the inheritance hierarchy now looks like this:

C < M' < S

[Note: Actually include delegates to append_features, which really does the above work, and just like almost everything else in Ruby, you can actually alter this behavior by overriding append_features, but that is advanced meta-magic.]

So, what are the practical implications of having a class that can be used in multiple places in the inheritance hierarchy? Well, you can use it to implement common behavior for unrelated classes.

Again, look at the Enumerable mixin: it provides common behavior for any object that conforms to the following protocol: it must have an each method that yields all elements one-by-one and returns self. That's it. There doesn't need to be any sort of inheritance relationship between the classes of those objects. All that is required is that they respond to each in an appropriate manner.

Which leads us to your question about interfaces: that's an interface. Although in Ruby, we usually call it protocol. Protocols in Ruby are very much like interfaces in C#, however, there is one crucial difference: there is no such thing as a protocol in Ruby. Protocols are latent, not manifest, they only exist in the programmer's head, in documentation, but not in the source code, and thus they cannot be checked by the language.

self.included – including class methods from a module in Ruby

What's the difference between the two examples?

The first code block adds the class methods in ClassMethods to the including class and calls the scope method on it as well. The second one does neither of these things and will result in a NoMethodError because the module has no scope class method. self.some_class_method will not be available on the including class once the module is included.

For the full story on how module inclusion works in Ruby, read my answer here:

Inheriting class methods from modules / mixins in Ruby

What's the point of self.included if a module's sole purpose is to be included?

Inclusion is not the only purpose of modules. They are also used for other things such as namespacing or simply storing various class methods that are then callable on the module itself.

Why doesn't Ruby include class methods automatically?

Theoretically Ruby could automatically add all class methods defined in a module to the including class, but in practice that would be a bad idea, because you would not get to choose anymore whether you want to include class methods — all class methods would be included every time, whether or not they are intended to be included. Consider this example:

module M
def self.class_method
"foo"
end

def self.configure_module
# add configuration for this module
end
end

class C
include M
end

Here, the configure_module method is obviously not supposed to be added to C, as its purpose is to set the configuration for the module object. Yet, if we had auto-inclusion for class methods, you would not be able to prevent it from being included.

But all instance methods are already included! How is that okay then?

Instance methods in a module are only really useful if they are included into a class, since modules cannot have instances, only classes can. So in a module every instance method is expected to be included somewhere to work.

A "class" method on a module is different, because it can be called on the module itself, so it can be used just fine regardless of whether it's also added to the including class. That is why it is better that you have a choice there.

Inheriting class methods from modules / mixins in Ruby

A common idiom is to use included hook and inject class methods from there.

module Foo
def self.included base
base.send :include, InstanceMethods
base.extend ClassMethods
end

module InstanceMethods
def bar1
'bar1'
end
end

module ClassMethods
def bar2
'bar2'
end
end
end

class Test
include Foo
end

Test.new.bar1 # => "bar1"
Test.bar2 # => "bar2"

How do I use the Enumerable mixin in my class?

It's easy, just include the Enumerable module and define an each instance method, which more often than not will just use some other class's each method. Here's a really simplified example:

class ATeam
include Enumerable

def initialize(*members)
@members = members
end

def each(&block)
@members.each do |member|
block.call(member)
end
# or
# @members.each(&block)
end
end

ateam = ATeam.new("Face", "B.A. Barracus", "Murdoch", "Hannibal")
#use any Enumerable method from here on
p ateam.map(&:downcase)

For further info, I recommend the following article: Ruby Enumerable Magic: The Basics.

In the context of your question, if what you expose through an accessor already is a collection, you probably don't need to bother with including Enumerable.



Related Topics



Leave a reply



Submit