Private Module Methods in Ruby
So this is something I’ve looked into many times over the years and have never found an answer to. But great news is that I’ve found a way!
It’s as simple as defining module methods as private within the singleton class. Here’s how I did it in my gem PolyBelongsTo
module PolyBelongsTo::Core extend ActiveSupport::Concern included do def self._pbt_polymorphic_orphans # some code here end def self._pbt_nonpolymorphic_orphans # some code here end class << self private :_pbt_polymorphic_orphans private :_pbt_nonpolymorphic_orphans end end end
My gem gets included into ActiveRecord::Base and these private methods are available for my other methods to use and my tests show that they are indeed private. One sample ActiveRecord table I’ve named Squishy and this is the Minitest test I wrote to prove it’s private.
it "keeps helper methods private" do Squishy.singleton_class.private_method_defined?(:_pbt_polymorphic_orphans).must_be_same_as true Squishy.singleton_class.method_defined?(:_pbt_polymorphic_orphans).must_be_same_as false Squishy.method_defined?(:_pbt_polymorphic_orphans).must_be_same_as false Squishy.singleton_class.private_method_defined?(:_pbt_nonpolymorphic_orphans).must_be_same_as true Squishy.singleton_class.method_defined?(:_pbt_nonpolymorphic_orphans).must_be_same_as false Squishy.method_defined?(:_pbt_nonpolymorphic_orphans).must_be_same_as false end
And it passes all green! My other methods that call these pass as well! Yay!
If you were to do this without the Rails “Concern” way of doing it your code would look more like.
module PolyBelongsTo::Core def self.included(base) def base._pbt_polymorphic_orphans # some code here end def base._pbt_nonpolymorphic_orphans # some code here end class << base private :_pbt_polymorphic_orphans private :_pbt_nonpolymorphic_orphans end end end
And anything you include it into will now have these private methods defined! Hope you enjoyed this! I’m very happy to have discovered it myself and hope it finds you well.
If you’re not planning on including the module you can do it like this.
module Example def self.x "hello" end def self.y "hello" end class << self private :x end end Example.x # NoMethodError: private method `x' called for B:Module Example.y # => "hello"
Please feel free to comment, share, subscribe to my RSS Feed, and follow me on twitter @6ftdan!
God Bless!
-Daniel P. Clark
Image by Richard Scott via the Creative Commons Attribution-NonCommercial-NoDerivs 2.0 Generic License.
Micah Geisel
May 2, 2015 - 3:13 pm
Also, http://ruby-doc.org/core-2.0.0/Module.html#method-i-private_class_method
Daniel P. Clark
May 2, 2015 - 5:36 pm
Yes thanks! They’ve added several ways of defining a private method in more recent Ruby versions. The approach I’ve shared here works with Ruby 1.8
Piotr Szotkowski
May 25, 2015 - 2:44 pm
In all of those cases presented in the blog my choice would be `module_function`, which makes the given `Module`’s methods callable on the `Module` itself and locally anywhere it’s included, but not from outside the places it’s included:
Daniel P. Clark
May 25, 2015 - 10:31 pm
Awesome! That’s definitely handy if you’d like to be able to include the behavior. In the last example I’ve shown of a non-inclusive module the method access is exclusive. Which is something I rather like myself.