I'd like to convert the constant FOO::BAR to the string "BAR".
This is the opposite of what constantize does and is very similar to demodulize, except I expect a string instead of the actual Module reference.
I was thinking I could make my own helper to do this, but I'm not able to get the "stringified" version of FOO::BAR.
Ideally, I'd like to avoid any 3rd party gems.
Example:
class FOO
BAR = {}
end
# this works
FOO #=> FOO
FOO.name #=> "FOO"
# this doesn't
FOO::BAR #=> {}
FOO::BAR.name #=> NoMethodError: undefined method `name' for {}:Hash
You can't pass constants, you can only pass objects. If you pass FOO::BAR to a method, you're not passing the constant, but the object that has been assigned to FOO::BAR, i.e. the hash.
In order to retrieve the constant's name an object has been assigned-to from the object itself, the object has to store the name somehow.
Modules do store the constant name they have been assigned-to (Ruby sets the name when a module is assigned to a constant for the first time). And because FOO is a module (classes are modules), you can call FOO.name and it returns "FOO". But that only works because the object "knows" its name.
From the built-in objects, only Module (and therefore Class) has a name method that works this way.
You could add a name method to the hash instance FOO::BAR is referring to, although this is probably not what you want:
def (FOO::BAR).name
'FOO::BAR'
end
FOO::BAR.name #=> "FOO::BAR"
Another way is to pass both, the constant (the object actually) and its module to a method:
def find_const(mod, obj)
mod.constants.find { |c| mod.const_get(c).equal?(obj) }
end
find_const(FOO, FOO::BAR) #=> :BAR
The method traverses the module's constants and returns the (first) constant that refers to the passed object.
class FOO
class BAR
end
end
FOO::BAR.to_s.split('::').last
#=> "BAR"
Note that the method Module#to_s "Returns a string representing this module or class. For basic classes and modules, this is the name". Module#name could be used in place of to_s.
Related
This question already has answers here:
Ruby what class gets a method when there is no explicit receiver?
(2 answers)
Closed 7 months ago.
In Ruby every method is assigned to an object (right?). Ruby provides a lot of "built in" methods and gives the ability to the user to create "user defined" methods.
Built in methods are all defined in a class like String, Integer, Array and so on. Built in methods are all invoked placing a dot after an object followed by the method call.
string = "example"
string = string.reverse
However, when I define a method with the syntax
def method_name (args)
#body
end
to which object is this method assigned? And why when I have to call a method that I have defined I don't use the "dot syntax" but I just write its name and pass it some arguments without applying it to an object, like this:
method_name args
In Ruby every method is assigned to an object (right?)
Incorrect. In Ruby, methods are assigned to modules (including classes). When you call a method on an object, Ruby runtime searches for the method along the object's class's ancestor chain (the object's singleton class -> the object's class ->
the superclass -> superclass's superclass -> ... -> BasicObject). If the method is found, it is bound to the object and gets called, otherwise the Ruby runtime searches for a special method called method_missing and bind it to the current object and calls it.
to which object is this method assigned?
It's assigned to the class Object, as a private instance method.
def foo
:foo
end
Object.private_instance_methods.grep(/foo/)
#=> [:foo]
I guess Ruby does this in order to make top-level "functions" look global.
class A
def self.a
foo
end
def a
foo
end
end
A.a #=> :foo
A.new.a #=> :foo
There is top-level object in Ruby -- main
def method_name(args)
# body
end
self
# => main
self.methods.grep(/method_name/)
# => [:method_name]
main is an instance of Object. Any methods defined in main become instance methods of Object
Object.private_instance_methods.grep(/method_name/)
# => [:method_name]
This makes them available everywhere (because all classes are descendants of Object), meaning that we can call the method without a receiver inside classes
For example
def foo
puts "foo"
end
class X
def y
foo
end
end
# will print foo
X.new.y
# will raise private method `foo' called for #<X:0x000055e406a0f060> (NoMethodError)
# to reproduce don't use irb, just usual file
X.new.foo
Read more
It seems like both of these methods return the same result (a human readable representation of the object and it's type). What is the differences between the methods?
class Foo
end
f = Foo.new
puts f.class <== puts Foo
puts f.class.inspect <== puts Foo
It seems like both of these methods return the same result (a human readable representation of the object and it's type).
No, they don't.
What is the differences between the methods?
Object#class returns the class of the receiver.
Module#inspect is an alias of Module#to_s and returns a human-readable string representation of the module. In particular, it returns the Module#name if it has one, and a unique representation otherwise. For singleton classes, it includes information about the object the singleton class is the singleton class of.
So, the two methods don't return the same result. In fact, they don't even return a result of the same class: Object#class returns an instance of the Class class, Module#inspect returns an instance of the String class.
Since puts needs a string, it calls the class's to_s method. I believe Class inherits the method from Module:
Returns a string representing this module or class. For basic classes and modules, this is the name. For singletons, we show information on the thing we’re attached to as well.
Also aliased as: inspect
Perhaps you intended to look at the object's methods?
class Foo
def initialize
#t = 'Junk'
end
end
f = Foo.new
puts f.class # => Foo
puts f.to_s # => #<Foo:0x007fce2503bbf0>
puts f.inspect # => #<Foo:0x007fce2503bbf0 #t="Junk">
Some classes like Integer able to create a instance by
Integer(1) #=> 1
It seems the class name works as method name.
How can I create a method like this and when should I use it instead of define a initialize method?
Integer is a Kernel method. In fact, it is defined as Kernel.Integer.
You can simply create a new method that acts as initializer for your custom class:
class Foo
def initialize(arg)
#arg = arg
end
end
def Foo(arg)
Foo.new(arg)
end
Foo("hello")
# => #<Foo:0x007fa7140a0e20 #arg="hello">
However, you should avoid to pollute the main namespace with such methods. Integer (and a few others) exists because the Integer class has no initializer.
Integer.new(1)
# => NoMethodError: undefined method `new' for Integer:Class
Integer can be considered a factory method: it attempts to convert the input into an Integer, and returns the most appropriate concrete class:
Integer(1).class
# => Fixnum
Integer(1000 ** 1000).class
# => Bignum
Unless you have a real reason to create a similar initializer, I'd just avoid it. You can easily create static methods attached to your class that converts the input into an instance.
It’s not a class, it’s a method (Kernel#Integer) that begins with a capital letter.
def Foo(x = 1)
"bar to the #{x}!"
end
Foo(10) #=> "bar to the 10!"
It can co-exist with a constant of the same name as well:
module Foo; end
Foo.new #=> #<Foo:0x007ffcdb5151f0>
Foo() #=> "bar to the 1!"
Generally, though, it’s thought that creating methods that begin with a capital letter is a bad idea and confusing.
What is difference between class and Class.new & module and Module.new?
I know that:
Class.new/Module.new create an anonymous class/module. When we assign it to constant for the first time it becomes name of that class/module. class/module do this automatically.
When we want to inherit, we can pass an argument: Class.new(ancestor). When we don't specify an ancestor, it is set to the Object. class use this syntax: class A < Ancestor
Class.new returns an object. class A returns nil. Same goes for modules.
Did I miss something?
The interesting point that you missed between class keyword and Class::new is - Class::new accepts block. So when you will be creating a class object using Class::new you can also access to the surrounding variables. Because block is closure. But this is not possible, when you will be creating a class using the keyword class. Because class creates a brand new scope which has no knowledge about the outside world. Let me give you some examples.
Here I am creating a class using keyword class :
count = 2
class Foo
puts count
end
# undefined local variable or method `count' for Foo:Class (NameError)
Here one using Class.new :
count = 2
Foo = Class.new do |c|
puts count
end
# >> 2
The same difference goes with keyword module and Module::new.
Class.new returns an object. class A returns nil. Same goes for modules.
That's wrong. A class/module definition returns the value of the last expression evaluated inside of the class/module body:
class Foo
42
end
# => 42
Typically, the last expression evaluated inside of a class/module body will be a method definition expression, which in current versions of Ruby returns a Symbol denoting the name of the method:
class Foo
def bar; end
end
# => :bar
In older versions of Ruby, the return value of a method definition expression was implementation-defined. Rubinius returned a CompiledMethod object for the method in question, whereas YARV and most others simply returned nil.
In Ruby, inside a class's instance method, we use a getter by
foo
and we use a setter by
self.foo = something
One doesn't need to have a self. and the other does, is there a way to make them look more similar, and not using something like self.foo as the getter, as it also looks verbose.
(update: note that getter and setter may simply get or set an instance variable, but they might also do a lot of work, such as going into the DB and check the existence of a record and if not, create it, etc)
Since local scope takes precedence, when you say foo = something, a local variable foo will be created and assigned the contents of something.
The reason you can write foo in order to use the getter is because Ruby will move up in scope when it can't find a variable with that name and it will eventually find the method.
If there is a local variable with the same name as the getter method, Ruby will use its value instead:
class Foo
attr_accessor :foo
def initialize
#foo = :one
end
def f
foo = :two
foo
end
end
Foo.new.f
# => :two
In order to make it clear that you want to access the setter, you must write self.foo = something. That will tell Ruby you want to execute the foo= method on the self object with something as parameter.
If you are willing to break the conventions, you can write your setters using jQuery style, using the same method for getter and setter, depending of whether it has arguments or not:
def foo *args
return #foo if args.empty?
#foo = args.first
end
# => nil
foo
# => nil
foo(:bar) # foo = :bar
# => :bar
foo
# => :bar
As far as I know, there isn't a way around this in Ruby. I'm pretty confident this is simply how Ruby evaluates expressions.
When given a value, Ruby will first check if there is a local variable within the context which matches the one being called. If there is (perhaps 'foo' in your case), that will be the value used. If there is no such value, then Ruby will try to look up the value as a method call (falling through to "self" as the caller). If no such method exists in the look up path, an error will be raised.
The need to use "self" in the setter is to avoid Ruby setting the value as a local variable, while the lack of the use of "self" only works in the getter instance when there is no local variable of the same name being used in that context. It is probably better and clearer, albeit slightly more verbose, to be explicit with your use of self as to avoid confusion about where values are coming from.