Search code examples
ruby-on-railsrubyoopprivate

Ruby protected constants, or similar implementation


I would like to implement the following:

module A
  class B
  end
  # can call A:B within module
end

# cannot call A:B outside of module (like private constant)

I basically want private constants but I would like to be able to call them with namespacing within the module.

It seems to me I need some sort of protected behaviour on the B constant within A, but as far as I am aware, Ruby does not have protected constants.

I am keen to hear ideas on how this can be implemented.


Solution

  • That can be done but I have no idea why you'd want to do it.

    module A
      class B
        def greeting
          puts "hi within #{self}"
        end
      end
      puts "constants within A = #{constants}"
      B.new.greeting
      # <more code>
      # lastly...
      const_set(:B, nil)
    end
    

    displays:

    constants within A = [:B]
    hi within #<A::B:0x00005b2a18ffc538>
    warning: already initialized constant A::B
    warning: previous definition of B was here
    

    Then,

    A::B.new.greeting
      NoMethodError (undefined method `new' for nil:NilClass)
    

    If desired, you can add '-W' or -W0 to the command line to suppress the warning messages.

    I understand ActiveSupport has a method Object::remove_constant allowing one to replace const_set(:B, nil) (or const_set("B", nil)) with:

    Object.public_send(:remove_const, :B)
    

    which may be preferable.