How to I make private class constants in Ruby
You can also change your constant into a class method:
def self.secret
'xxx'
end
private_class_method :secret
This makes it accessible within all instances of the class, but not outside.
Why would you private encapsulate a private constant?
The reason for private_constant
is to prevent other code from accessing the constant directly.
some_constant
might return the constant today, but it's not obligated to do that. If programming-by-contract then it's obligated to return a hash in that form, the origin of which is irrelevant.
For example, you have that code today, but what about tomorrow it evolves to:
class Foo < Bar
SM_CONSTANT = {
a: { name: 'A', priority: 2 },
b: { name: 'B', priority: -1 }
}.freeze
private_constant :SM_CONSTANT
private
def some_constant
SM_CONSTANT.map { |k,o| [ k.to_s, o[:name] ] }.to_h
end
end
Where the internals have completely changed but to outside code nothing has, the same calls produce the same results. This is why encapsulation is important. It gives you the freedom to iterate and rework code within a particular context without concerning yourself about breaking other things.
If code accessed SM_CONSTANT
directly it'd have to be re-written to accept this new structure.
Constants or class variables in ruby?
The main thing is that by using the CONSTANT notation, you're making it clear to the reader. the lower case, frozen string gives the impression is might be settable, forcing someone to go back and read the RDoc.
Accessing a class's constants
What you posted should work perfectly:
class Foo
CONSTANT_NAME = ["a", "b", "c"]
end
Foo::CONSTANT_NAME
# => ["a", "b", "c"]
How to implement private inner class in Ruby
why am I able to create Node objects outside the LinkedList class even though it is declared as private?
Because in ruby constants ignore "regular" visibility modifiers. They're always public, regardless of which section they're in. To make them private, use private_constant
. Call this inelegant design or whatever, but that's how it is.
Also, be warned that even with private_constant
, the privateness means very little. Basically, the only thing it does is hide the constant from lists (LinkedList.constants
) and direct resolution (LinkedList::Node
). If one knows the name, they will be able to access it.
class LinkedList
class Node
attr_accessor :val, :next
end
private_constant :Node
end
LinkedList.const_get('Node') # => LinkedList::Node
How to namespace constants inside anonymous class definitions?
When creating anonymous classes through Class.new, they don't seem to have their own namespace for constants
Sure, by the definition of the word “anonymous.” Compare two following snippets:
class C1; puts "|#{name}|"; end
#⇒ |C1|
C2 = Class.new { puts "|#{name}|" }
#⇒ ||
Unless assigned to the constant, the class has no name and hence all constants defined inside go to Object
namespace. That said, the warning here is actually pointing out to error and Object::FOO = "bar"
overrides Object::FOO = "foo"
constant.
That said, one cannot use constants in this scenario. Use class-level instance variables instead, or construct unique constant names manually (I would advise avoiding polluting Object
class with a bunch of unrelated constants, though.)
How to create a private class method?
private
doesn't seem to work if you are defining a method on an explicit object (in your case self
). You can use private_class_method
to define class methods as private (or like you described).
class Person
def self.get_name
persons_name
end
def self.persons_name
"Sam"
end
private_class_method :persons_name
end
puts "Hey, " + Person.get_name
puts "Hey, " + Person.persons_name
Alternatively (in ruby 2.1+), since a method definition returns a symbol of the method name, you can also use this as follows:
class Person
def self.get_name
persons_name
end
private_class_method def self.persons_name
"Sam"
end
end
puts "Hey, " + Person.get_name
puts "Hey, " + Person.persons_name
Access a private constant from module
I'd suggest writing it like this so you won't have to change anything other than include B
if you rename B
:
module B
def access_private_here
puts self.class::MY_CONST
end
end
class A
include B
private
MY_CONST = "cat"
end
A.new.access_private_here #=> "cat"
How to make a module constant also visible within an eigenclass?
Solution
class << self
def eigen_scope
p [__method__, hello(self::NAME)]
#=> [:eigen_scope, "Hello Otto!"]
end
end
Why does self::NAME
work?
A::NAME
would be the easiest, hard-coded version.B::NAME
would also work, becauseB
includesA
- Inside
eigen_scope
,self
isB
, soself::NAME
works as well self::NAME
would also work inself.class_scope
self::NAME
wouldn't work ininstance_scope
: aB
instance is not a class/module.
Why doesn't NAME
work?
Here's a very good explanation.
constant lookup searches for constants that are defined in
Module.nesting
,Module.nesting.first.ancestors
, and
Object.ancestors
ifModule.nesting.first
is nil or a module
self
is the same in class_scope
and eigen_scope
.
Module.nesting
is different though :
[B]
forclass_scope
[#<Class:B>, B]
foreigen_scope
So Module.nesting.first.ancestors
is :
[B, A, Object, Kernel, BasicObject]
forclass_scope
[#<Class:B>, A::ClassMethods, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]
foreigen_scope
A
isn't searched, but A::ClassMethods
!
So you could define :
module A
module ClassMethods
NAME = 'Bob'
end
end
Related Topics
How to Get the Intersection, Union, and Subset of Arrays in Ruby
File.Open, Open and Io.Foreach in Ruby, What Is the Difference
How to Resolve "Gpg: Command Not Found" Error During Rvm Installation
How to Update Ruby with Homebrew
Rails, How to Render a View/Partial in a Model
How to Log Every Method That's Called in a Ruby Program
Best Practice to Mark Deprecated Code in Ruby
Capistrano Asks for Password When Deploying, Despite Ssh Keys
Factory Girl - What's the Purpose
Check If a Hash's Keys Include All of a Set of Keys
Force Bundle Install to Use Https:// Instead of Git:// for Github-Based Gems
Detect Number of Cpus Installed
How to Avoid Duplicates in a Has_Many :Through Relationship