Reputation: 2390
Is there a concise way to limit method visibility within the module while including it? In other words, I'd like to limit polluting the class with helper methods only used in the included module.
module Bar
def call
hide_me
end
private
# make this method only callable within this module
def hide_me
'visible'
end
end
class Foo
include Bar
def unrelated_method
hide_me
end
end
# that's ok
Foo.new.call #=> 'visible'
# that's not
Foo.new.unrelated_method #=> 'visible'
I'm ok with calling it via Bar.instance_method(:hide_me).bind(self).call
, I just don't want to worry about accessing or redefining a helper method from some module.
Upvotes: 0
Views: 83
Reputation: 110685
One can do what you want by including the module to the class and then undefining the unwanted included methods.
First construct a module.
module M
def cat
puts "meow"
end
def dog
puts "woof"
end
def owl
puts "who?"
end
private
def frog
puts "ribbit"
end
def pig
puts "oink"
end
end
Confirm the methods now exist.
M.instance_methods(false)
#=> [:cat, :dog, :owl]
M.private_instance_methods(false)
#=> [:frog, :pig]
Create the class, including the module M
.
class C
def froggie
frog
end
def cat
puts "meow-meow"
end
include M
end
Check the instance methods.
C.instance_methods & [:cat, :dog, :owl, :froggie]
#=> [:cat, :froggie, :dog, :owl]
C.private_instance_methods & [:frog, :pig]
#=> [:frog, :pig]
and confirm :cat
is owned by C
and not by M
.
C.instance_method(:cat).owner
#=> C
Now use the method Module#undef_method to undefine the unwanted methods from the module.
class C
[:cat, :owl, :pig].each { |m|
undef_method(m) unless instance_method(m).owner == self }
end
The unless...
clause is needed so that the instance method :cat
defined in C
is not undefined.
Confirm the methods were undefined.
C.instance_methods & [[:cat, :dog, :owl, :froggie]
#=> [:cat, :froggie, :dog]
C.private_instance_methods & [:frog, :pig]
#=> [:frog]
Execute the methods.
c = C.new
c.cat
#=> "meow-meow"
c.dog
#=> "woof"
c.froggie
#=> "ribbit"
Upvotes: 0
Reputation: 5345
You can wrap a class into the module and use private methods within the class, like so:
module Bar
def call
BarClass.new.call
end
class BarClass
def call
hide_me
end
private
def hide_me
puts "invisible"
end
end
end
class Foo
include Bar
def call_bar
call
end
def this_method_fails
hide_me
end
end
Upvotes: 2