I am having a hard time understanding attr_accessor
in Ruby. Can someone explain this to me?
相关问题
- How to specify memcache server to Rack::Session::M
- Why am I getting a “C compiler cannot create execu
- reference to a method?
- ruby 1.9 wrong file encoding on windows
- gem cleanup shows error: Unable to uninstall bundl
相关文章
- Ruby using wrong version of openssl
- Difference between Thread#run and Thread#wakeup?
- how to call a active record named scope with a str
- “No explicit conversion of Symbol into String” for
- Segmentation fault with ruby 2.0.0p247 leading to
- How to detect if an element exists in Watir
- uninitialized constant Mysql2::Client::SECURE_CONN
- ruby - simplify string multiply concatenation
I faced this problem as well and wrote a somewhat lengthy answer to this question. There are some great answers on this already, but anyone looking for more clarification, I hope my answer can help
Initialize Method
Initialize allows you to set data to an instance of an object upon creation of the instance rather than having to set them on a separate line in your code each time you create a new instance of the class.
In the code above we are setting the name “Denis” using the initialize method by passing Dennis through the parameter in Initialize. If we wanted to set the name without the initialize method we could do so like this:
In the code above, we set the name by calling on the attr_accessor setter method using person.name, rather than setting the values upon initialization of the object.
Both “methods” of doing this work, but initialize saves us time and lines of code.
This is the only job of initialize. You cannot call on initialize as a method. To actually get the values of an instance object you need to use getters and setters (attr_reader (get), attr_writer(set), and attr_accessor(both)). See below for more detail on those.
Getters, Setters (attr_reader, attr_writer, attr_accessor)
Getters, attr_reader: The entire purpose of a getter is to return the value of a particular instance variable. Visit the sample code below for a breakdown on this.
In the code above you are calling the methods “item_name” and “quantity” on the instance of Item “example”. The “puts example.item_name” and “example.quantity” will return (or “get”) the value for the parameters that were passed into the “example” and display them to the screen.
Luckily in Ruby there is an inherent method that allows us to write this code more succinctly; the attr_reader method. See the code below;
This syntax works exactly the same way, only it saves us six lines of code. Imagine if you had 5 more state attributable to the Item class? The code would get long quickly.
Setters, attr_writer: What crossed me up at first with setter methods is that in my eyes it seemed to perform an identical function to the initialize method. Below I explain the difference based on my understanding;
As stated before, the initialize method allows you to set the values for an instance of an object upon object creation.
But what if you wanted to set the values later, after the instance was created, or change them after they have been initialized? This would be a scenario where you would use a setter method. THAT IS THE DIFFERENCE. You don’t have to “set” a particular state when you are using the attr_writer method initially.
The code below is an example of using a setter method to declare the value item_name for this instance of the Item class. Notice that we continue to use the getter method attr_reader so that we can get the values and print them to the screen, just in case you want to test the code on your own.
The code below is an example of using attr_writer to once again shorten our code and save us time.
The code below is a reiteration of the initialize example above of where we are using initialize to set the objects value of item_name upon creation.
attr_accessor: Performs the functions of both attr_reader and attr_writer, saving you one more line of code.
Attributes and accessor methods
Attributes are class components that can be accessed from outside the object. They are known as properties in many other programming languages. Their values are accessible by using the "dot notation", as in object_name.attribute_name. Unlike Python and a few other languages, Ruby does not allow instance variables to be accessed directly from outside the object.
In the above example, c is an instance (object) of the Car class. We tried unsuccessfully to read the value of the wheels instance variable from outside the object. What happened is that Ruby attempted to call a method named wheels within the c object, but no such method was defined. In short, object_name.attribute_name tries to call a method named attribute_name within the object. To access the value of the wheels variable from the outside, we need to implement an instance method by that name, which will return the value of that variable when called. That's called an accessor method. In the general programming context, the usual way to access an instance variable from outside the object is to implement accessor methods, also known as getter and setter methods. A getter allows the value of a variable defined within a class to be read from the outside and a setter allows it to be written from the outside.
In the following example, we have added getter and setter methods to the Car class to access the wheels variable from outside the object. This is not the "Ruby way" of defining getters and setters; it serves only to illustrate what getter and setter methods do.
The above example works and similar code is commonly used to create getter and setter methods in other languages. However, Ruby provides a simpler way to do this: three built-in methods called attr_reader, attr_writer and attr_acessor. The attr_reader method makes an instance variable readable from the outside, attr_writer makes it writeable, and attr_acessor makes it readable and writeable.
The above example can be rewritten like this.
In the above example, the wheels attribute will be readable and writable from outside the object. If instead of attr_accessor, we used attr_reader, it would be read-only. If we used attr_writer, it would be write-only. Those three methods are not getters and setters in themselves but, when called, they create getter and setter methods for us. They are methods that dynamically (programmatically) generate other methods; that's called metaprogramming.
The first (longer) example, which does not employ Ruby's built-in methods, should only be used when additional code is required in the getter and setter methods. For instance, a setter method may need to validate data or do some calculation before assigning a value to an instance variable.
It is possible to access (read and write) instance variables from outside the object, by using the instance_variable_get and instance_variable_set built-in methods. However, this is rarely justifiable and usually a bad idea, as bypassing encapsulation tends to wreak all sorts of havoc.
Let's say you have a class
Person
.Obviously we never defined method
name
. Let's do that.Aha, we can read the name, but that doesn't mean we can assign the name. Those are two different methods. The former is called reader and latter is called writer. We didn't create the writer yet so let's do that.
Awesome. Now we can write and read instance variable
@name
using reader and writer methods. Except, this is done so frequently, why waste time writing these methods every time? We can do it easier.Even this can get repetitive. When you want both reader and writer just use accessor!
Works the same way! And guess what: the instance variable
@name
in our person object will be set just like when we did it manually, so you can use it in other methods.That's it. In order to understand how
attr_reader
,attr_writer
, andattr_accessor
methods actually generate methods for you, read other answers, books, ruby docs.attr_accessor is just a method. (The link should provide more insight with how it works - look at the pairs of methods generated, and a tutorial should show you how to use it.)
The trick is that
class
is not a definition in Ruby (it is "just a definition" in languages like C++ and Java), but it is an expression that evaluates. It is during this evaluation when theattr_accessor
method is invoked which in turn modifies the current class - remember the implicit receiver:self.attr_accessor
, whereself
is the "open" class object at this point.The need for
attr_accessor
and friends, is, well:Ruby, like Smalltalk, does not allow instance variables to be accessed outside of methods1 for that object. That is, instance variables cannot be accessed in the
x.y
form as is common in say, Java or even Python. In Rubyy
is always taken as a message to send (or "method to call"). Thus theattr_*
methods create wrappers which proxy the instance@variable
access through dynamically created methods.Boilerplate sucks
Hope this clarifies some of the little details. Happy coding.
1 This isn't strictly true and there are some "techniques" around this, but there is no syntax support for "public instance variable" access.
Hmmm. Lots of good answers. Here is my few cents on it.
attr_accessor
is a simple method that helps us in cleaning(DRY-ing) up the repeatinggetter and setter
methods.So that we can focus more on writing business logic and not worry about the setters and getters.
If you are familiar with OOP concept, You must familiar with getter and setter method. attr_accessor does the same in Ruby.
Getter and Setter in General Way
Setter Method
Getter method
Getter and Setter method in Ruby