What does attr mean in Ruby? [duplicate] - ruby

In Ruby there are four different getter and setter methods for instance variables, attr, attr_reader, attr_writer, and attr_accessor. The question is, is in Ruby attr :dilithium, the same as attr_reader :dilithium, and identical to attr_accessor :dilithium if an additional parameter true is passed? That is to say is
class Enterprise
attr :dilithium, true
identical to
class Enterprise
attr_accessor :dilithium
Are the two functions attr and attr_accessor more or less redundant?

One difference is that attr_accessor and friends are clearer, and the optional boolean argument to attr is now deprecated. Other than that, and the fact that attr has no documentation, there's no real difference.

In Ruby 1.8, attr can define only a single attribute, with an optional true to create a setter . In 1.9 it behaves like attr_reader:it allows for multiple attributes. As #Linuxios says, the optional boolean is deprecated.

If you look at the C code in Ruby 2.3.0, you will see that attr and attr_reader are actually doing the same thing (except for the deprecated code path). They are essentially equivalent functions.
For me, the main differences are:
attr is a bit easier to write down as it's shorter. I like the way it feels in the context of functional/immutable programming too (in those contexts, attr_writer and attr_accessor are irrelevant and thus using attr_reader feels verbose and redundant).
attr with multiple instance variables makes it hard to document, except in very specific situations, e.g.
# The coordinates in WGS84.
attr :x, :y
# The location name.
attr :name
# The popularity of the location.
attr :popularity
It would be harder to document :name and :popularity independently if they were on the same line attr :name, :popularity.
Apart from that it boils down to personal preference. There is in practice no performance difference or any other difference.

attr and attr_accessor are methods in Ruby that are used to define instance variables in classes.
attr creates a simple getter method that returns the value of an instance variable with the same name as the symbol passed as an argument. For example:
class MyClass
attr :my_variable
def initialize
#my_variable = "Hello World"
end
end
my_object = MyClass.new
puts my_object.my_variable # outputs "Hello World"
attr_accessor creates both getter and setter methods for an instance variable with the same name as the symbol passed as an argument. For example:
class MyClass
attr_accessor :my_variable
def initialize
#my_variable = "Hello World"
end
end
my_object = MyClass.new
puts my_object.my_variable # outputs "Hello World"
my_object.my_variable = "Goodbye World"
puts my_object.my_variable # outputs "Goodbye World"
In the example above, my_object.my_variable can be read and written. The attr_accessor method creates both getter and setter methods, allowing the value of the instance variable to be read and written.

Related

What is the difference between the following two? [duplicate]

In Ruby there are four different getter and setter methods for instance variables, attr, attr_reader, attr_writer, and attr_accessor. The question is, is in Ruby attr :dilithium, the same as attr_reader :dilithium, and identical to attr_accessor :dilithium if an additional parameter true is passed? That is to say is
class Enterprise
attr :dilithium, true
identical to
class Enterprise
attr_accessor :dilithium
Are the two functions attr and attr_accessor more or less redundant?
One difference is that attr_accessor and friends are clearer, and the optional boolean argument to attr is now deprecated. Other than that, and the fact that attr has no documentation, there's no real difference.
In Ruby 1.8, attr can define only a single attribute, with an optional true to create a setter . In 1.9 it behaves like attr_reader:it allows for multiple attributes. As #Linuxios says, the optional boolean is deprecated.
If you look at the C code in Ruby 2.3.0, you will see that attr and attr_reader are actually doing the same thing (except for the deprecated code path). They are essentially equivalent functions.
For me, the main differences are:
attr is a bit easier to write down as it's shorter. I like the way it feels in the context of functional/immutable programming too (in those contexts, attr_writer and attr_accessor are irrelevant and thus using attr_reader feels verbose and redundant).
attr with multiple instance variables makes it hard to document, except in very specific situations, e.g.
# The coordinates in WGS84.
attr :x, :y
# The location name.
attr :name
# The popularity of the location.
attr :popularity
It would be harder to document :name and :popularity independently if they were on the same line attr :name, :popularity.
Apart from that it boils down to personal preference. There is in practice no performance difference or any other difference.
attr and attr_accessor are methods in Ruby that are used to define instance variables in classes.
attr creates a simple getter method that returns the value of an instance variable with the same name as the symbol passed as an argument. For example:
class MyClass
attr :my_variable
def initialize
#my_variable = "Hello World"
end
end
my_object = MyClass.new
puts my_object.my_variable # outputs "Hello World"
attr_accessor creates both getter and setter methods for an instance variable with the same name as the symbol passed as an argument. For example:
class MyClass
attr_accessor :my_variable
def initialize
#my_variable = "Hello World"
end
end
my_object = MyClass.new
puts my_object.my_variable # outputs "Hello World"
my_object.my_variable = "Goodbye World"
puts my_object.my_variable # outputs "Goodbye World"
In the example above, my_object.my_variable can be read and written. The attr_accessor method creates both getter and setter methods, allowing the value of the instance variable to be read and written.

Why are setter methods not used in initialization?

Recently I've been reading "Practical Object Oriented Design in Ruby", and I noticed one of the best practices was to use accessor methods instead of directly grabbing the #instance_variable. For example:
class Foo
attr_accessor :bar
def initialize(my_argument)
#bar = my_argument
end
# bad
# def lorem_ipsum
# #bar * 999
# end
# good
def lorem_ipsum
bar * 999
end
end
It makes sense to keep things DRY, and, in case I need to process #bar somehow before actually grabbing its value. However, I noticed that the initialize method sets the value of the #bar instance variable directly:
class Foo
attr_accessor :bar
def initialize(my_argument)
#bar = my_argument #<-- why isn't self.bar = my_argument used here?
end
Is there a reason for this? Shouldn't the setter method be used instead of directly using the = operator to set the value of the instance variable?
You're right, it would make much more sense to do
class Foo
attr_accessor :bar
def initialize(my_argument)
self.bar = my_argument
end
end
Arguments differ as to whether you should respect encapsulation within the object itself or not, but if you believe in that, then, yes, you should do this.
The initializer SETS the value upon initialization. The accessor lets you access (read/write) via the symbol after the object is already instantiated.
This post might help you understand:
What is attr_accessor in Ruby?
Actually, the setter can be used in initialize the same as in other methods, but setter cannot be used without a receiver.
I think you can use a_foo.bar= or self.bar=, but cannot use bar= without a receiver, because, in the later case, bar will be treated as a local variable rather than a setter method:
class Song
attr_accessor :name
def initialize(name)
self.name = name
end
def test_setter1(value)
#name = value
end
def test_setter2(value)
name = value #name is local variable
end
end
s = Song.new("Mike")
p s
s.test_setter1("John")
p s
s.test_setter2("Rosy")
p s
This results in:
#<Song:0x23a50b8 #name="Mike">
#<Song:0x23a50b8 #name="John">
#<Song:0x23a50b8 #name="John">
While you can use the setter in the initialization as shown in #uncutstone's answer, you cannot use it as you've proposed in the comment in your code.
The problem is that Ruby would interpret:
bar = my_argument
as an assignment to the bar local variable rather than an invocation of the bar= method.
This is discussed rather extensively in "Why do Ruby setters need "self." qualification within the class?".

attr vs attr_accessor

In Ruby there are four different getter and setter methods for instance variables, attr, attr_reader, attr_writer, and attr_accessor. The question is, is in Ruby attr :dilithium, the same as attr_reader :dilithium, and identical to attr_accessor :dilithium if an additional parameter true is passed? That is to say is
class Enterprise
attr :dilithium, true
identical to
class Enterprise
attr_accessor :dilithium
Are the two functions attr and attr_accessor more or less redundant?
One difference is that attr_accessor and friends are clearer, and the optional boolean argument to attr is now deprecated. Other than that, and the fact that attr has no documentation, there's no real difference.
In Ruby 1.8, attr can define only a single attribute, with an optional true to create a setter . In 1.9 it behaves like attr_reader:it allows for multiple attributes. As #Linuxios says, the optional boolean is deprecated.
If you look at the C code in Ruby 2.3.0, you will see that attr and attr_reader are actually doing the same thing (except for the deprecated code path). They are essentially equivalent functions.
For me, the main differences are:
attr is a bit easier to write down as it's shorter. I like the way it feels in the context of functional/immutable programming too (in those contexts, attr_writer and attr_accessor are irrelevant and thus using attr_reader feels verbose and redundant).
attr with multiple instance variables makes it hard to document, except in very specific situations, e.g.
# The coordinates in WGS84.
attr :x, :y
# The location name.
attr :name
# The popularity of the location.
attr :popularity
It would be harder to document :name and :popularity independently if they were on the same line attr :name, :popularity.
Apart from that it boils down to personal preference. There is in practice no performance difference or any other difference.
attr and attr_accessor are methods in Ruby that are used to define instance variables in classes.
attr creates a simple getter method that returns the value of an instance variable with the same name as the symbol passed as an argument. For example:
class MyClass
attr :my_variable
def initialize
#my_variable = "Hello World"
end
end
my_object = MyClass.new
puts my_object.my_variable # outputs "Hello World"
attr_accessor creates both getter and setter methods for an instance variable with the same name as the symbol passed as an argument. For example:
class MyClass
attr_accessor :my_variable
def initialize
#my_variable = "Hello World"
end
end
my_object = MyClass.new
puts my_object.my_variable # outputs "Hello World"
my_object.my_variable = "Goodbye World"
puts my_object.my_variable # outputs "Goodbye World"
In the example above, my_object.my_variable can be read and written. The attr_accessor method creates both getter and setter methods, allowing the value of the instance variable to be read and written.

How does Ruby use symbols to reference variable names?

When we are defining getter and setter methods for name in the following code:
class Animal
attr_accessor :name
def initialize(name)
#name = name
end
end
what is happening internally? How is Ruby able to take a symbol and match it with a variable?
It uses instance_variable_get and instance_variable_set for that.
Update: as Andrew Marshall noted, not exactly. Most ruby core methods are defined in C, but the result is essentially the same.
One could define attr_accessor and friends as follows:
def self.attr_accessor(*names)
names.each do |name|
define_method(name) do
instance_variable_get("##{name}")
end
define_method("#{name}=") do |new_value|
instance_variable_set("##{name}", new_value)
end
end
end
Note that I've also used define_method here to define the accessor methods.
I recommend that you take a look at some introductory texts about ruby metaprogramming, such as "Don’t Know Metaprogramming In Ruby?".
It doesn't match it with a variable, attr_accessor does essentially this (it's actually written in C, but I've written it's roughly Ruby translation here):
def attr_accessor(var_name)
ivar_name = :"##{var_name}"
define_method(var_name) do
instance_variable_get ivar_name
end
define_method("#{var_name}=") do |value|
instance_variable_set ivar_name, value
end
end
As you can see, it simply uses the symbol passed to create two methods. It doesn't do anything fancy with the symbol, and is mostly just passing it through. Note, also, that all instance variables "exist" by default and are set to nil, so this will never blow up.

YARD: document custom getter/setter pair like attr_accessor

I'm using YARD to document my project. YARD document attributes created with
attr_accessor :some_attribute
in a separate section "Instance Attribute Summary". Now I have another attribute, but with custom setter and getter
def some_other_attribute
# ...
end
def some_other_attribute= value
# ...
end
so basically my question is, how can I get YARD to document this pair of setter/getter just like attr_accessor in the previous case, and list some_other_attribute within "Instance Attribute Summary"?
As of 0.8 (which is in pre-release right now), the #!attribute directive is the recommended way to denote that an object is an attribute. The #attr_* tags are deprecated in favour of this directive. You could also do (in 0.8.0+):
# #!parse attr_accessor :some_attribute
To parse code that isn't necessarily executed by Ruby. Prior to 0.8, you could just add the attr_accessor directly and then redefine the setter/getter as follows:
class MyClass
attr_accessor :foo
def foo; something_else end
def foo=(v) something_else(v) end
end
Ruby shouldn't mind, except that in ruby -w it will warn about method redefinitions. If this bugs you, you can add undef foo, foo= in there too. It's a little messy (if you care about -w), which is why we added things like #!parse and #!attribute.
You should be able to use the #attr tag on the class:
# #attr [String] name The name of this object.
class MyClass
def name
end
def name=
end
end
There are other tags (like #attr_reader and #attr_writer) than can also be helpful.

Resources