Reputation: 58778
In Ruby, <ClassName>.constants
is useful to inspect classes:
> Numeric.constants(false)
=> [:KILOBYTE, :MEGABYTE, :GIGABYTE, :TERABYTE, :PETABYTE, :EXABYTE]
> Object.constants(false)
=> [:Object, :Module, ...]
This is defined in Module
:
> Object.method(:constants)
=> #<Method: Class(Module)#constants>
I'd like to add another method to print a hash with all the constants and their values. Here's the result so far:
def Module.constants_hash(inherit=true)
self.constants(inherit).inject({}) do |hash, constant|
hash[constant] = self::const_get(constant)
hash
end
end
This works for Module
(although it has no constants, so the result is just an empty hash), but it's not inherited:
> Object.constants_hash(false)
NoMethodError: undefined method `constants_hash' for Object:Class
from (pry):117:in `<main>'
I can of course change the class name in the code to e.g. Object
to make the call work, but is it possible to make all the dependent modules inherit the new method as well? In other words, is it possible to add a method at runtime which is then inherited by classes which require
the modified class?
I'd rather not overload the original Module.constants
, to avoid changing the API.
Upvotes: 2
Views: 544
Reputation: 13719
Object
is an instance of type Class
. Class
class is inherited from Module
. In order for Object.constants_hash
to work, you need to define instance method of Class
or Module
classes:
class Module
def constants_hash(inherit=true)
self.constants(inherit).inject({}) do |hash, constant|
hash[constant] = self::const_get(constant)
hash
end
end
end
In you code you just add constants_hash
to a singleton class of Module
instance (of type Class
), this is why you don't get expected result.
Upvotes: 4
Reputation: 211560
You might have better luck by declaring this method in a module, then mixing it in to each context as required:
module ConstantsHash
def constants_hash(inherit = true)
Hash[
self.constants(inherit).collect do |constant|
[ constant, const_get(constant) ]
end
]
end
end
Module.extend(ConstantsHash)
Object.extend(ConstantsHash)
puts Object.constants_hash.inspect
As a note, using Hash[]
instead of inject({ })
does seem to work better in cases like this.
Upvotes: 0