How do I determine the current open class in Ruby?
Inside the class itself:
class_name = self.class
On an initialized object named obj:
class_name = obj.class
Inside of a class definition body, self refers to the class itself. Module#name will tell you the name of the class/module, but only if it actually has one. (In Ruby, there is no such thing as a "class name". Classes are simply objects just like any other which get assigned to variables just like any other. It's just that if you happen to assign a class object to a constant, then the name method will return the name of that constant.)
Example:
puts class Foo
name
end
# Foo
But:
bar = Class.new
bar.name # => nil
BAR = bar
bar.name #=> 'BAR'
if you have obj = SomeClass.new you get the class with obj.class
If you're looking to compare via the class name (string):
class Foo
def my_class_name_is
self.class.name
end
end
Foo.new.my_class_name_is
=> "Foo"
In my case, the name method was overwrote, I find to_s give me this same result
class Foo
puts self.name
puts self.to_s
end
#=> Foo
#=> Foo
Related
I know it's possible to define instance methods using class_eval. Is it possible to define class methods within the context of class_eval?
Yes, it is possible:
class Foo
end
Foo.class_eval do
def self.bar
puts "I'm a class method defined using class_eval and self"
end
def baz
puts "I'm an instance method defined using class_eval without self"
end
end
Foo.bar # => "I'm a class method defined using class_eval and self"
foo = Foo.new
foo.baz # => "I'm an instance method defined using class_eval without self"
As far as I can tell, this is because within class_eval, self is the Foo class, and doing def Foo.bar would create a class method.
Foo.class_eval do
...
end
is identical to:
class Foo
...
end
We need Module#class_eval to operate on a variable that holds the name of a class. For example, if:
klass = Foo
you can write:
klass.class_eval do
...
end
whereas the keyword class demands a constant.
Here class_eval does two things:
it changes self to the value of klass (Foo); and then it
"opens" the value of klass (Foo) in the same way the keyword class does.
I have an object that is using attr_accessor. I want to be able to call a method on that object with a variable with #send. My problem is that the = method doesn't seem to work.
class Foo
attr_accessor :bar
end
class Test_class
def test_method(x)
f = Foo.new
f.send(x)
f.send(x) = "test" #this doesnt work
f.send("#{x} =") "test" #this also doesn't work
# How can I set bar?
end
end
t = Test_class.new
t.test_method("bar")
You want f.send "#{x}=", "test". In Ruby, method names may include punctuation, such as = or !. The methods created by attr_accessor :bar are simply named bar and bar=. In fact, attr_accessor :bar is just shorthand for:
def bar
#bar
end
def bar=(value)
#bar = value
end
When you're calling foo.bar = "baz", you're actually calling the #bar= method with foo as the receiver and "bar" as the first parameter to the function - that is, foo.bar=("baz"). Ruby just provides syntactic sugar for methods ending in = so that you can write the more natural-looking form.
I have a data object that contains dozens of attr_accessor fields for various inputs. Can I somehow define the class so that all setters for all fields will e.g. set the value as an empty string instead of the attempted nil?
Here's a little module to do it:
module NilToBlankAttrAccessor
def nil_to_blank_attr_accessor(attr)
attr_reader attr
define_method "#{attr}=" do |value|
value = '' if value.nil?
instance_variable_set "##{attr}", value
end
end
end
Just mix it in:
class Foo
extend NilToBlankAttrAccessor
nil_to_blank_attr_accessor :bar
end
And use it:
foo = Foo.new
foo.bar = nil
p foo.bar # => ""
foo.bar = 'abc'
p foo.bar # => "abc"
How it works
NilToBlankAttrAccessor#nil_to_blank_attr_accessor first defines the attr_reader normally:
attr_reader attr
Then it defines the writer by defining a method with the same name as the accessor, only with an "=" at the end. So, for attribute :bar, the method is named bar=
define_method "#{attr}=" do |value|
...
end
Now it needs to set the variable. First it turns nil into an empty string:
value = '' if value.nil?
Then use instance_variable_set, which does an instance variable assignment where the instance variable isn't known until runtime.
instance_variable_set "##{attr}", value
Class Foo needs nil_to_blank_attr_accessor to be a class method, not an instance method, so it uses extend instead of include:
class Foo
extend NilToBlankAttrAccessor
...
end
Instead of doing
object.foo = given_input
you should do
object.foo = given_input.nil? ? "" : given_input
or if you want to turn false into "" as well, then
object.foo = given_input || ""
Where is instance variable initialized as nil first time?
Can I redefine it as other value by default for all instances?
For example:
class Class
#some code here or maybe in an Object class
end
class Foo1
attr_accessor :bar
end
class Foo2
attr_accessor :bar
end
p Foo1.new.bar # result is not nil
p Foo2.new.bar # result is not nil
This can be done by modifying the reader:
class Class
def attr_accessor(attr_name)
...
define_method "#{attr_name}" do
if instance_variable_get "##{attr_name}_history"
instance_variable_get "##{attr_name}_history"
else
"Not nil"
end
end
...
end
end
But this doesn't help in understanding the core of Ruby.
Many thanks!
If you want to set default values, you can assign them in an initialize method of a class.
For example:
class Test
attr_accessor :bar
def initialize
#bar = 'bar'
end
end
Test.new.bar
# => "bar"
Remember that attr_accessor :bar gives you helper methods to set and get the underlying instance variable #bar.
If you want default values for lots of classes, you can have them inherit from a class that sets the instance variables as not nil:
class Foo < Test
end
Foo.new.bar
# => "bar"
Define a new method in class Class. Get instance variables through :instance_variables and set them to anything you like by using :instance_variable_set(:#var,default_value)
class Class
alias oldNew new
def new(*args)
result = oldNew(*args)
default = 2354 # set default here
a = result.instance_variables
a.each do
|d|
result.instance_variable_set(d,default)
end
return result
end
end
(Corrected following Jörg W Mittag's comment)
No you cannot. Instance variables are set evaluated to nil when you call them without assigning a value to them.
You can dynamically define a class method for a class like so:
class Foo
end
bar = %q{def bar() "bar!" end}
Foo.instance_eval(bar)
But how do you do the opposite: remove/undefine a class method? I suspect Module's remove_method and undef_method methods might be able to be used for this purpose, but all of the examples I've seen after Googling for hours have been for removing/undefining instance methods, not class methods. Or perhaps there's a syntax you can pass to instance_eval to do this as well.
Thanks in advance.
class Foo
def self.bar
puts "bar"
end
end
Foo.bar # => bar
class <<Foo
undef_method :bar
end
# or
class Foo
singleton_class.undef_method :bar
end
Foo.bar # => undefined method `bar' for Foo:Class (NoMethodError)
When you define a class method like Foo.bar, Ruby puts it Foo's singleton class. Ruby can't put it in Foo, because then it would be an instance method. Ruby creates Foo's singleton class, sets the superclass of the singleton class to Foo's superclass, and then sets Foo's superclass to the singleton class:
Foo -------------> Foo(singleton class) -------------> Object
super def bar super
There are a few ways to access the singleton class:
class <<Foo,
Foo.singleton_class,
class Foo; class << self which is commonly use to define class methods.
Note that we used undef_method, we could have used remove_method. The former prevents any call to the method, and the latter only removes the current method, having a fallback to the super method if existing. See Module#undef_method for more information.
This also works for me (not sure if there are differences between undef and remove_method):
class Foo
end
Foo.instance_eval do
def color
"green"
end
end
Foo.color # => "green"
Foo.instance_eval { undef :color }
Foo.color # => NoMethodError: undefined method `color' for Foo:Class
You can remove a method in two easy ways. The drastic
Module#undef_method( )
removes all methods, including the inherited ones. The kinder
Module#remove_method( )
removes the method from the receiver, but it
leaves inherited methods alone.
See below 2 simple example -
Example 1 using undef_method
class A
def x
puts "x from A class"
end
end
class B < A
def x
puts "x from B Class"
end
undef_method :x
end
obj = B.new
obj.x
result -
main.rb:15:in
': undefined methodx' for # (NoMethodError)
Example 2 using remove_method
class A
def x
puts "x from A class"
end
end
class B < A
def x
puts "x from B Class"
end
remove_method :x
end
obj = B.new
obj.x
Result -
$ruby main.rb
x from A class
I guess I can't comment on Adrian's answer because I don't have enough cred, but his answer helped me.
What I found: undef seems to completely remove the method from existence, while remove_method removes it from that class, but it will still be defined on superclasses or other modules that have been extened on this class, etc.
If you would like to remove method with name what calculate dinamically, you should use eigenclasses like:
class Foo
def self.bar
puts "bar"
end
end
name_of_method_to_remove = :bar
eigenclass = class << Foo; self; end
eigenclass.class_eval do
remove_method name_of_method_to_remove
end
this way is better than others answers, becouse here i used class_eval with block. As you now block see current namespace, so you could use your variables to remove methods dinamically
Object.send(:remove_const, :Foo)