JP.
JP.

Reputation: 5594

Writing Ruby Libraries - hiding methods from outside the module

I'm writing a Ruby library which has a module with a bunch of classes inside it. Many of these classes need to be usable and modifiable by calling scripts, but I don't want (some of) the initializers to be visible/callable:

module MyLib
  class Control
    def initialize
      # They can use this
    end

    def do_stuff
      Helper.new('things')
    end
  end

  class Helper
    # Shouldn't be visible 
    def initialize(what)
      @what = what
    end

    def shout
      @what
    end
  end
end

c = MyLib::Control.new
h = c.do_stuff
p h.shout
# => "things"
# ^ All of this is desired

# v This is undesirable
p MyLib::Helper.new('!')
# => <MyLib::Helper @what='!'>

If it's a simple thing, then I'd also appreciate the generated RDoc not even include the .new method for the Helper class either. Any ideas?

Thanks for reading!

Upvotes: 5

Views: 1746

Answers (2)

Mark Rushakoff
Mark Rushakoff

Reputation: 258228

My original answer was completely wrong, as @Matthew pointed out. But there are other workarounds. For instance, you can assign an anonymous class to a class variable on Control, and still define methods as normal by using class_eval:

module MyLib
  class Control
    def initialize
    end

    def do_stuff
      @@helper.new('things')
    end

    @@helper = Class.new
    @@helper.class_eval do
      def initialize(what)
        @what = what
      end

      def shout
        @what
      end
    end
  end
end

The snippet

c = MyLib::Control.new
h = c.do_stuff
p h.shout

still writes "things", but now there's no way to access @@helper except through the class variable. If someone really wants to access it my reopening the Control class or using class_eval, there's nothing to stop them, but that's just something you have to deal with in a dynamic language.

I chose to assign the anonymous class to a class variable so that it would only be created once; but if you don't care about redefining the anonymous class many times, there's no reason it couldn't be an instance variable.

Upvotes: 3

Matthew Flaschen
Matthew Flaschen

Reputation: 284836

Ruby has access control.

Upvotes: 2

Related Questions