Reputation: 333
I'm playing with some of the very basics of ruby mixins, and for some reason can't access behavior from my module.
Running this on Ruby Fiddle:
module Cats
MEOW = "meow meow meow"
def Cats.meow?
return Cats::MEOW
end
end
class Example
include Cats
def sample
return "it's a sample"
end
end
e = Example.new
puts e.sample
puts e.meow?
This keeps returning NoMethodError: undefined method 'meow?' for #
My understanding of how mixins should work from tutorialspoint makes me feel like I should be able to validly call e.meow?
, and get back the same result I would get from calling Cats.meow?
.
Here's the code in RubyFiddle.
Incredibly basic, but any ideas where I'm falling down here?
Upvotes: 0
Views: 156
Reputation: 41
As a general rule to using include
and extend
in Ruby:
If you want to use your module as a namespace
module Outer
module Inner
def self.my_method
"namespaced method!"
end
end
end
You use it like this Outer::Inner::my_method
or Outer::Inner.my_method
.
And if you want to use the module as a mixin:
# In some cases it makes sense to use names ending in -able, since it expreses
# what kind of messages you can send to an instance or class that mixes
# this module in.
# Like Devise's Recoverable module: https://github.com/plataformatec/devise/blob/f39c6fd92774cb66f96f546d8d5e8281542b4e78/lib/devise/models/recoverable.rb#L24
module Fooable
def foo
"#{self} has been foo'ed!"
end
end
Then you can include
it (instances of Something obtain #foo):
class Something
include Fooable # Now Something.new can receive the #foo message.
end
Something.new.foo
=> "#<Something:0x0055c2dc104650> has been foo'ed!"
Or you can extend it (Something itself obtains #foo as a class message):
class Something
extend Fooable # Now Something can receive the #foo message.
end
Something.foo
=> "Something has been foo'ed!"
Upvotes: 1
Reputation: 333
As it turns out, I was being overly specific when defining Cats.meow?
. If you want to use a module as a mixin you'll want to define your methods more generally, not with respect to their specific module namespace.
So instead of
def Cats.meow?
...
end
it should have been
def meow?
...
end
This lets you call e.meow?
, since the method definition no longer limits it just to the Cats
namespace.
Whoops.
Upvotes: 2