Can someone suggest a good, ruby-idiomatic, way of avoiding this?
class Foo
attr_accessor :bar
end
a = {one: 1}
x = Foo.new; x.bar = a
x.bar[:two] = 2
p a #=> {one: 1, two: 2}
I could simply not allow the users of a class to access its attributes, which solves the problem...in this case. (What about passing parameters to a method?) Anyway, avoiding everything but attr_reader, and using that only on non-mutable attributes, doesn't seem very Ruby-ish.
Or, I can just not write any code which mutates values, which appeals, but is not exactly easy to do in Ruby.
I could systematically dup or clone every parameter my class is given -- except that those methods don't work on Nilclass, Fixnums, Symbols, etc -- and worse, responds_to?(:dup) == true for those types. (Also, neither dup nor clone do a deep copy.)
In the example above I modify the bar attribute in the caller, but the problem remains the same if the code is in the class, or if I use a method on the class instead of attr_accessor : If I want a class which can accept a value and do something with it, and if for some reason I have to do that by mutating that value somewhere -- is there an idiomatic way in ruby to ensure that I don't infect the caller with that mutated value?
In Ruby we are supposed not to care about the type of the incoming data very much, but it looks as if I have to care about it quite a lot in order to tell how to make this value I want to mutate safe. If it's a NullObject or a Fixnum or a Symbol it's fine, otherwise I can dup it ... unless I need to deep copy it.
That can't be right, can it?
Edit: After Some More Thought
Sergio is of course right -- sometimes you want this behaviour. Not because using the side effect in your code is a good idea, but because sometimes the class you are passing a message to needs a live reference to an object that might change afterwards.
The only time this behaviour is going to be problematic is when you are passing an Enumerable. If I pass an Array or a Hash, I really don't want the receiver to modify that. So my takeaway is:
Do what Sergio said and code defensively whenever I pass stuff to a receiver, just in case the person who coded it hasn't been careful.
Implement a blanket rule in my own classes: dup all incoming Enumerables.
It is responsibility of the caller to shield itself from code being called. Let's say, you have some command line options parsing code. You got this hash of parameters and you want to do some validation (or something). Now, the validating code was written by some other guy who likes to do things in-place for "efficiency". So it is likely that your hash will be mutated and you won't be able to use it later.
Solution? Pass a copy.
validate_params! Marshal.load(Marshal.dump(params)) # deep copy
Note that in some cases mutation is desirable. So it must be the caller who controls the effect (allows or prevents it).
I would consider using freeze:
class Foo
attr_reader :bar
def bar=(value)
#bar = value.freeze # You may need to freeze nested values too
end
end
a = { one: 1 }
x = Foo.new
x.bar = a
x.bar[:two] = 2
# raises: can't modify frozen Hash
Or if you prefer to not change Foo, freeze the value when assigning:
class Foo
attr_accessor :bar
end
a = {one: 1}
x = Foo.new
x.bar = a.freeze
x.bar[:two] = 2
# raises: can't modify frozen Hash
Just want to enquire what the right practice is.
My preference is to use procs, simply because I think that defining methods inside of methhods is a bit untidy and should be done only when necessary. To get around it, I simply use procs.
What is the right / better way to do it and why? (apart from the proc's ability to access the main method's variables defined before itself)
def meth( params_prime )
calculations = do_something_with_whatever
def sub_meth( params_sub )
do_something_with_params_sub
end
sub_meth_params(calculations) # is this better?
proc1 = proc{ |params_sub| do_something_with_params_sub }
proc1.call(calculations) # or is this?
end
It is not clear what your specific use-case is, but I would definitely go for procs or lambdas. There is less overhead when defining a proc or lambda dynamically, they are passable, so if needed you could return them and they could be used outside the function.
Using "def" exposes the method as an instance method outside of the current method scope (so in the containing class, which could be Object in your case). This may or may not be with you want. If you want to use an anonymous function only available in the local scope, use a lambda.
Also Proc vs Lambda: I generally prefer to use lambdas since they behave a little more "predictable", meaning: as you would expect (check passed variables, and return just returns from the lambda, proc returns from the called scope). But from your example it is hard to deduce what would apply. I think the key-difference is: lambas are ment to be passed around, and thus behave a little more sanely. If this is not your use-case, use Proc :) (a write-up of the difference).
If you want to use sub_func to encapsulate it from call from other methods you can use a class to group function and sub_func together and make sub_func private. Otherwise if you want to pass this function as a parameter further you can declare it as lamda.
def func params_prime
sub_func = ->(params_sub){do_something_with_params}
sub_func.call(params_prime)
end
Defining methods inside methods is a feature of Ruby that may have its use. But something is telling me that you are asking a very advanced question while you are still a beginner level Rubyist. Do you know what default definee is? If not, check this article by Yugui.
Procs are very important in Ruby, but newbies tend to use them instead of defining methods in appropriate objects, which is the exact smell I'm getting from your question. The normal way of doing things in OO languages of Ruby family is to define methods on objects:
class Foo
def bar *params
# do something with params
end
end
Since you do not understand the meaning of defining methods inside methods, refrain from doing it for the next 6 months. Once you understand objects, you can start experimenting with this very advanced feature again.
APPENDIX:
Since you demonstrated intrest, let me show you that using def in def at the top level is a frownable-upon thing to do. Normally, when you define a method on some class without further adornment, it becomes a public instance method of that class:
class X
def foo; "foo" end
end
X.instance_methods.include? :foo
#=> true
When you use def in a def, the definee for the inner def is going to be X:
class X
def bar
def baz
"baz"
end
"bar"
end
end
When you execute the above code, instance method #bar becomes defined on X:
X.instance_methods.include? :bar
#=> true
But #baz not yet:
X.instance_methods.include? :baz
#=> false
Only after you call #bar at least once does the method become defined on X:
X.new.bar
#=> "bar"
X.instance_methods.include? :baz
#=> true
And now I would like to ask you to appreciate how terrible thing just happened: An instance just modified its mother class. That's a violation. A violation of such a basic principle of OO design, that I'm not even sure it has a name. This technique is great for obfuscated coding competitions, but in production, it's taboo. Ruby gives you the freedom to break that taboo, gives you the rope to hang yourself on, but you don't do it under any kind of normal circumstances.
So what can be worse than a def inside a def in a class definition? The answer is, a def inside a def at the top level. Let me show you why. Normally, when you define methods with def at the top level, the default definee is Object, but the top level defnitions become private instance methods of object. This is to prevent the unintended consequence of top level defs, because almost all Ruby objects inherit from Object. For example, if you define:
class Object
def foo; "foo" end
end
Now all your objects will respond to foo:
foo #=> "foo"
1.foo #=> "foo"
[].foo #=> "foo
When we define methods at the top level, we usually just intend to use the method at the top level, and don't want every single object to inherit it. For that reason, top level defs become private:
hello #=> NameError: undefined local variable or method `hello' for main:Object
1.hello #=> NoMethodError: undifined method 'hello' for 1:Fixnum
Now we use def at the top level:
def hello; "hello" end
We can see that method #hello is has not become an instance methods of Object:
Object.instance_methods.include? :hello
#=> false
Mysteriously, it became its private method:
Object.private_instance_methods.include? :hello
#=> true
This way, we avoid the unintended consequence of defining #hello method for every single object. But the inheritance is there. The error message has changed:
1.hello #=> NoMethodError: private method 'hello' called for 1:Fixnum
And we can forcibly call the method via #send:
1.send :hello
#=> "hello"
Mysteriously, at the top level, we are allowed to call this private method without #send:
hello
#=> "hello"
And now, what happens when you do def in def at the top level:
def bar
def baz; "baz" end
"bar"
end
You define a private instance method Object#bar in an expected way. But when you call it, alas, the top level magic no longer works and a public method Object#baz gets defined:
bar #=> "bar"
This way, not just the top level, but every single Ruby object got polluted with your #baz method:
1.baz #=> "baz"
Class.baz #=> "baz"
This is why I told you to refrain from using this idiom until you progress from the level of unconscious incompetence to the level of conscious incompetence. I recommend you to read more about top level methods in Ruby.
I know there are "instance methods", "class methods" but what are these types of methods called, for eg:
s1 = "This is my STRING!"
def s1.m1
downcase
end
p s1 # => "This is my STRING!"
p s1.m1 # => "this is my string!"
What type of method is the "m1" method called on the s1 "instance" of the "string" class? It's really weird because I didn't know this was possible at all if I try:
s2 = "This is ANOTHER string"
s2.m1 # => Won't work!
Which kind of makes sense, but not sure why defining methods like m1 on instances on a class are useful at all.
They are called singleton methods, and can be defined as follows:
class Person
def favorite_meal
"Big Mac"
end
end
Fred, Joe = 2.times.map { Person.new }
def Fred.favorite_meal
"Le Big Mac"
end
Joe.favorite_meal #=> Big Mac
Fred.favorite_meal #=> Le Big Mac
Other ways to define the same singleton method would be:
Fred.define_singleton_method :favorite_meal do "Le Big Mac" end
And:
class << Fred
def favorite_meal
"Le Big Mac"
end
end
May the force be with you.
UPDATE: Answering the 2 questions from the comment.
Let me start by the 2nd one. It is up to you, whether you use a constant or a variable. It is perfectly OK to write fred = Person.new. But:
Objects with distinct properties often deserve proper names, which are properly capialized.
There is a useful gem I wrote, y_support/name_magic, that works by assigning to constants.
Install it by gem install y_support, and try:
require 'y_support/name_magic'
class Dog
include NameMagic
def speak; puts "Bow wow!" end
end
Spot, Rover = 2.times.map { Dog.new }
Now the Dog class knows its instances, and the instances know their names.
Dog.instances.map { |dog| dog.name } #=> :Spot, :Rover
Dog.instances.names # the simpler way to say the same
This is not useful in this particular example (and extremely useful elsewhere), but in any case, it gave me a habit of giving objects with personalities capitlized proper names.
As for the 1st question, def Fred.foobar is the most basic, one-off singleton method definition. If you want to define several singleton methods, or alias, or include a module in the singleton class, use class << Fred:
module Foo
def bar; "Fretbar!" end
end
class << Fred
include Foo
alias le_favorite favorite_meal
end
Fred.bar #=> Fretbar!
Fred.le_favorite #=> "Le Big Mac"
The most advanced things are possible with Fred.define_singleton_method syntax, and with the 4th way, which I have not mentioned earlier:
local_var = 42
Fred.singleton_class.class_exec do
define_method :baz do local_var + 1 end
end
Fred.baz #=> 43
This way uses closures, which retain binding to the variable local_var. Try it out
local_var = 32
Fred.baz #=> 33
So this is what's special about the syntax with closures, and it is often a godsend that magically solves nasty programming problems.
They are called object Singleton Methods.
A example i can think of where you could use that:
You have a special logging class and you have to limit the logging to only one instance because you want your logging file to be clean and tidy.
Maybe not the best example, but if your interested in the use cases, look for use cases for the Singleton Pattern and you should find your answers there.
They are called singleton method. Here is some way to check those:
s1 = "This is my STRING!"
def s1.m1
downcase
end
klass= s1.singleton_class # => #<Class:#<String:0x902d4e8>>
klass.instance_methods(false) # => [:m1]
s1.method(:m1).owner # => #<Class:#<String:0x902d4e8>>
s1.singleton_methods # => [:m1]
but not sure why defining methods like m1 on instances on a class are useful at all.
These singleton method(m1) can only be called only by s1,as you defined it inside the singleton class of s1. But not by any other instances of the String class. These are needed when you are having some behaviors that are unique to the object,irrespective of the fact that,if they are belonging to the same class or different class(s).
s2.m1 # => Won't work!
Because you didn't define it inside the singleton class of s1.
"(...)but not sure why defining methods like m1 on instances on a class are useful at all."
It makes this behaviour possible:
class Test
def self.some_meth
end
end
Test is just an instance of Class, and some_method is added to this specific instance.
p Test.singleton_methods #=> [:some_meth]
I am having a hard time understanding attr_accessor in Ruby.
Can someone explain this to me?
Let's say you have a class Person.
class Person
end
person = Person.new
person.name # => no method error
Obviously we never defined method name. Let's do that.
class Person
def name
#name # simply returning an instance variable #name
end
end
person = Person.new
person.name # => nil
person.name = "Dennis" # => no method error
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.
class Person
def name
#name
end
def name=(str)
#name = str
end
end
person = Person.new
person.name = 'Dennis'
person.name # => "Dennis"
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.
class Person
attr_reader :name
attr_writer :name
end
Even this can get repetitive. When you want both reader and writer just use accessor!
class Person
attr_accessor :name
end
person = Person.new
person.name = "Dennis"
person.name # => "Dennis"
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.
class Person
attr_accessor :name
def greeting
"Hello #{#name}"
end
end
person = Person.new
person.name = "Dennis"
person.greeting # => "Hello Dennis"
That's it. In order to understand how attr_reader, attr_writer, and attr_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 the attr_accessor method is invoked which in turn modifies the current class - remember the implicit receiver: self.attr_accessor, where self 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 Ruby y is always taken as a message to send (or "method to call"). Thus the attr_* 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.
attr_accessor is (as #pst stated) just a method. What it does is create more methods for you.
So this code here:
class Foo
attr_accessor :bar
end
is equivalent to this code:
class Foo
def bar
#bar
end
def bar=( new_value )
#bar = new_value
end
end
You can write this sort of method yourself in Ruby:
class Module
def var( method_name )
inst_variable_name = "##{method_name}".to_sym
define_method method_name do
instance_variable_get inst_variable_name
end
define_method "#{method_name}=" do |new_value|
instance_variable_set inst_variable_name, new_value
end
end
end
class Foo
var :bar
end
f = Foo.new
p f.bar #=> nil
f.bar = 42
p f.bar #=> 42
attr_accessor is very simple:
attr_accessor :foo
is a shortcut for:
def foo=(val)
#foo = val
end
def foo
#foo
end
it is nothing more than a getter/setter for an object
Basically they fake publicly accessible data attributes, which Ruby doesn't have.
It is just a method that defines getter and setter methods for instance variables. An example implementation would be:
def self.attr_accessor(*names)
names.each do |name|
define_method(name) {instance_variable_get("##{name}")} # This is the getter
define_method("#{name}=") {|arg| instance_variable_set("##{name}", arg)} # This is the setter
end
end
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
class Person
def name
#name
end
def name=(str)
#name = str
end
end
person = Person.new
person.name = 'Eshaan'
person.name # => "Eshaan"
Setter Method
def name=(val)
#name = val
end
Getter method
def name
#name
end
Getter and Setter method in Ruby
class Person
attr_accessor :name
end
person = Person.new
person.name = "Eshaan"
person.name # => "Eshaan"
Simple Explanation Without Any Code
Most of the above answers use code. This explanation attempts to answer it without using any, via an analogy/story:
Outside parties cannot access internal CIA secrets
Let's imagine a really secret place: the CIA. Nobody knows what's happening in the CIA apart from the people inside the CIA. In other words, external people cannot access any information in the CIA. But because it's no good having an organisation that is completely secret, certain information is made available to the outside world - only things that the CIA wants everyone to know about of course: e.g. the Director of the CIA, how environmentally friendly this department is compared to all other government departments etc. Other information: e.g. who are its covert operatives in Iraq or Afghanistan - these types of things will probably remain a secret for the next 150 years.
If you're outside the CIA you can only access the information that it has made available to the public. Or to use CIA parlance you can only access information that is "cleared".
The information that the CIA wants to make available to the general public outside the CIA are called: attributes.
The meaning of read and write attributes:
In the case of the CIA, most attributes are "read only". This means if you are a party external to the CIA, you can ask: "who is the director of the CIA?" and you will get a straight answer. But what you cannot do with "read only" attributes is to make changes changes in the CIA. e.g. you cannot make a phone call and suddenly decide that you want Kim Kardashian to be the Director, or that you want Paris Hilton to be the Commander in Chief.
If the attributes gave you "write" access, then you could make changes if you want to, even if you were outside. Otherwise, the only thing you can do is read.
In other words accessors allow you to make inquiries, or to make changes, to organisations that otherwise do not let external people in, depending on whether the accessors are read or write accessors.
Objects inside a class can easily access each other
On the other hand, if you were already inside the CIA, then you could easily call up your CIA operative in Kabul because this information is easily accessible given you are already inside. But if you're outside the CIA, you simply will not be given access: you will not be able to know who they are (read access), and you will not be able to change their mission (write access).
Exact same thing with classes and your ability to access variables, properties and methods within them. HTH! Any questions, please ask and I hope i can clarify.
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.
class Person
def initialize(name)
#name = name
end
def greeting
"Hello #{#name}"
end
end
person = Person.new("Denis")
puts person.greeting
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:
class Person
attr_accessor :name
# def initialize(name)
# #name = name
# end
def greeting
"Hello #{name}"
end
end
person = Person.new
person.name = "Dennis"
puts person.greeting
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.
class Item
def initialize(item_name, quantity)
#item_name = item_name
#quantity = quantity
end
def item_name
#item_name
end
def quantity
#quantity
end
end
example = Item.new("TV",2)
puts example.item_name
puts example.quantity
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;
class Item
attr_reader :item_name, :quantity
def initialize(item_name, quantity)
#item_name = item_name
#quantity = quantity
end
end
item = Item.new("TV",2)
puts item.item_name
puts item.quantity
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.
class Item
attr_reader :item_name
def item_name=(str)
#item_name = (str)
end
end
The code below is an example of using attr_writer to once again shorten our code and save us time.
class Item
attr_reader :item_name
attr_writer :item_name
end
item = Item.new
puts item.item_name = "TV"
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.
class Item
attr_reader :item_name
def initialize(item_name)
#item_name = item_name
end
end
item = Item.new("TV")
puts item.item_name
attr_accessor: Performs the functions of both attr_reader and attr_writer, saving you one more line of code.
I think part of what confuses new Rubyists/programmers (like myself) is:
"Why can't I just tell the instance it has any given attribute (e.g., name) and give that attribute a value all in one swoop?"
A little more generalized, but this is how it clicked for me:
Given:
class Person
end
We haven't defined Person as something that can have a name or any other attributes for that matter.
So if we then:
baby = Person.new
...and try to give them a name...
baby.name = "Ruth"
We get an error because, in Rubyland, a Person class of object is not something that is associated with or capable of having a "name" ... yet!
BUT we can use any of the given methods (see previous answers) as a way to say, "An instance of a Person class (baby) can now have an attribute called 'name', therefore we not only have a syntactical way of getting and setting that name, but it makes sense for us to do so."
Again, hitting this question from a slightly different and more general angle, but I hope this helps the next instance of class Person who finds their way to this thread.
Simply put it will define a setter and getter for the class.
Note that
attr_reader :v is equivalant to
def v
#v
end
attr_writer :v is equivalant to
def v=(value)
#v=value
end
So
attr_accessor :v which means
attr_reader :v; attr_writer :v
are equivalant to define a setter and getter for the class.
Simply attr-accessor creates the getter and setter methods for the specified attributes
Another way to understand it is to figure out what error code it eliminates by having attr_accessor.
Example:
class BankAccount
def initialize( account_owner )
#owner = account_owner
#balance = 0
end
def deposit( amount )
#balance = #balance + amount
end
def withdraw( amount )
#balance = #balance - amount
end
end
The following methods are available:
$ bankie = BankAccout.new("Iggy")
$ bankie
$ bankie.deposit(100)
$ bankie.withdraw(5)
The following methods throws error:
$ bankie.owner #undefined method `owner'...
$ bankie.balance #undefined method `balance'...
owner and balance are not, technically, a method, but an attribute. BankAccount class does not have def owner and def balance. If it does, then you can use the two commands below. But those two methods aren't there. However, you can access attributes as if you'd access a method via attr_accessor!! Hence the word attr_accessor. Attribute. Accessor. It accesses attributes like you would access a method.
Adding attr_accessor :balance, :owner allows you to read and write balance and owner "method". Now you can use the last 2 methods.
$ bankie.balance
$ bankie.owner
Despite the large number of existing answers, none of them seems to me to explain the actual mechanism involved here. It's metaprogramming; it takes advantage of the following two facts:
You can modify a module / class on the fly
A module / class declaration is itself executable code
Okay, so imagine the following:
class Nameable
def self.named(whatvalue)
define_method :name do whatvalue end
end
end
We are declaring a class method named which, when called with a value, creates an instance method called name which returns that value. That is the metaprogramming part.
Now we'll subclass that class:
class Dog < Nameable
named "Fido"
end
What on earth did we just do? Well, in the class declaration, executable code executes with reference to the class. So the bare word named is actually a call to the class method named, which we inherited from Nameable; and we are passing the string "Fido" as the argument.
And what does the class method named do? It creates an instance method called name, which returns that value. So now, behind the scenes, Dog has a method that looks like this:
def name
"Fido"
end
Don't believe me? Then watch this little move:
puts Dog.new.name #=> Fido
Why did I tell you all that? Because what I just did with named for Nameable is almost exactly what attr_accessor does for Module. When you say attr_accessor you are calling a class method (inherited from Module) that creates instance methods. In particular, it creates a getter and setter method for the instance property whose name you provide as argument, so that you don't have to write those getter and setter methods yourself.
Defines a named attribute for this module, where the name is symbol.id2name, creating an instance variable (#name) and a corresponding access method to read it. Also creates a method called name= to set the attribute.
module Mod
attr_accessor(:one, :two)
end
Mod.instance_methods.sort #=> [:one, :one=, :two, :two=]
To summarize an attribute accessor aka attr_accessor gives you two free methods.
Like in Java they get called getters and setters.
Many answers have shown good examples so I'm just going to be brief.
#the_attribute
and
#the_attribute=
In the old ruby docs a hash tag # means a method.
It could also include a class name prefix...
MyClass#my_method
I am new to ruby and had to just deal with understanding the following weirdness. Might help out someone else in the future. In the end it is as was mentioned above, where 2 functions (def myvar, def myvar=) both get implicitly for accessing #myvar, but these methods can be overridden by local declarations.
class Foo
attr_accessor 'myvar'
def initialize
#myvar = "A"
myvar = "B"
puts #myvar # A
puts myvar # B - myvar declared above overrides myvar method
end
def test
puts #myvar # A
puts myvar # A - coming from myvar accessor
myvar = "C" # local myvar overrides accessor
puts #myvar # A
puts myvar # C
send "myvar=", "E" # not running "myvar =", but instead calls setter for #myvar
puts #myvar # E
puts myvar # C
end
end
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.
class Car
def initialize
#wheels = 4 # This is an instance variable
end
end
c = Car.new
c.wheels # Output: NoMethodError: undefined method `wheels' for #<Car:0x00000000d43500>
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.
class Car
def wheels # getter method
#wheels
end
def wheels=(val) # setter method
#wheels = val
end
end
f = Car.new
f.wheels = 4 # The setter method was invoked
f.wheels # The getter method was invoked
# Output: => 4
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.
class Car
attr_accessor :wheels
end
f = Car.new
f.wheels = 4
f.wheels # Output: => 4
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.
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 repeating getter and setter methods.
So that we can focus more on writing business logic and not worry about the setters and getters.
The main functionality of attr_accessor over the other ones is the capability of accessing data from other files.
So you usually would have attr_reader or attr_writer but the good news is that Ruby lets you combine these two together with attr_accessor. I think of it as my to go method because it is more well rounded or versatile.
Also, peep in mind that in Rails, this is eliminated because it does it for you in the back end. So in other words: you are better off using attr_acessor over the other two because you don't have to worry about being to specific, the accessor covers it all. I know this is more of a general explanation but it helped me as a beginner.
Hope this helped!
Learning ruby. I'm under the impression that boolean attributes should be named as follows:
my_boolean_attribute?
However, I get syntax errors when attempting to do the following:
class MyClass
attr_accessor :my_boolean_attribute?
def initialize
:my_boolean_attribute? = false
end
end
Apparently ruby is hating the "?". Is this the convention? What am I doing wrong?
Edit: three-years later; the times, they are a-changin'…
Julik's answer is the simplest and best way to tackle the problem these days:
class Foo
attr_accessor :dead
alias_method :dead?, :dead # will pick up the reader method
end
My answer to the original question follows, for posterity…
The short version:
You can't use a question mark in the name of an instance variable.
The longer version:
Take, for example, attr_accessor :foo — it's simply conceptually a bit of syntactic sugar for the following:
def foo
#foo
end
def foo=(newfoo)
#foo = newfoo
end
Furthermore, the question-mark suffix is mostly just a convention to indicate that the return value of a method is a boolean.
The best approximation I can make of what you're going for here…
class MyClass
def initialize
#awesome = true
end
def awesome?
#awesome
end
end
In this case, there may be a case to be made for using attr_accessor — after all, it may be explicit that you're working directly with a boolean attribute. Generally, I save the question-mark suffix for when I am implementing a method whose boolean return value is based on slightly more complex conditions than just the value of an attribute.
Cheers!
Edit, two years later, after a recent comment:
Ruby enforces certain naming conventions. Symbols in Ruby can't have question marks. Thus invocations of :my_boolean_attribute? both will fail with a NameError. Edit: not correct, just use the quoted syntax for a symbol, e.g., :"my_attribute?"
Symbols are immutable, attempting to assign to one will throw a SyntaxError.
The easiest way to quickly add a "question method" is to use aliasing for your reader method
class Foo
attr_accessor :dead
alias_method :dead?, :dead # will pick up the reader method
end
The attr_accessor symbol implies that the variable name is #my_boolean_attribute, so that's what you should be setting (not the symbol).
Also, you can't use ? for variables, just method names.
? is convention for methodnames, not variables. You can't use an instance variable named #foo?, however you could use a variable named #foo and name the (manually created) getter method foo? if you wanted to.
Monkey-patching metaprogramming - maybe it can be made more elegant, this is only a quick draft, and I haven't done metaprogramming for a little while...
# inject the convenience method into the definition of the Object class
class Object
def Object::bool_attr(attrname)
class_eval { define_method(attrname.to_s,
lambda { instance_variable_get('#' + attrname.to_s.chop) }) }
class_eval { define_method(attrname.to_s.chop+"=",
lambda { |x| instance_variable_set('#'+attrname.to_s.chop, x) }) }
end
end
### somewhere later
class MyClass
bool_attr :my_boolean_attribute?
def initialize
#my_boolean_attribute = true
end
end
# yet even more later
foo = MyClass.new
bar = MyClass.new
foo.my_boolean_attribute = 1
puts foo.my_boolean_attribute?
puts bar.my_boolean_attribute?
With this approach, you can be DRY and get the nice questionmark too. You just might need to pick a better name than "bool_attr", like, "bool_attr_accessor" or something similar.
The definitions that I made are a bit cranky, in a sense that the question mark is present in the original symbol. Probably a cleaner approach would be to avoid the questionmark in the symbol name and append it during the definition of the method - should be less confusing.
Oh, and almost forgot to include the obligatory link: Seeing metaclasses clearly
I looked through the answers, and while the accepted answer is on-target, it introduces "extra" noise in the class. The way I'd suggest solving this issue is:
class Animal
attr_writer :can_swim
def initialize(animal_type_name)
#can_swim = true
#animal_type_name = animal_type_name
end
def can_swim?
#can_swim
end
def to_s
#animal_type_name
end
end
dog = Animal.new('Dog in a bag')
dog.can_swim = false
puts "Can this #{dog} Swim? --- [#{dog_without_legs.can_swim? ? 'YEP!' : 'NOPE!'}]"