When you use attr_accessor :venue
, you're essentially doing this.
def venue
@venue
end
def venue=(value)
@venue = value
end
When you do attr_writer :venue
, you're doing
def venue=(val)
@venue = val
end
When you do attr_reader :venue
, you're doing
def venue
@venue
end
Note that an @instance_variable
is nil
by default, or if it's uninitialized. To see this in action, type irb
in your terminal and press enter. Then, type a single @
, and spam a bunch of characters after it. @ausdhyf934234092348
will be nil.
When you're inside Ticket#initialize
, you're acting as an instance of the object, thus self
will return the current instance. self.class
will return the class, and give you access to any class-level methods.
class Ticket
VENUE_SIZES = [:small, :large]
def self.venue_sizes
VENUE_SIZES
end
def initialize(venue, date)
# ...
self.venue_sizes # NoMethodError
self.class.venue_sizes # [:small, :large]
end
end
Going up the chain, if you're acting as the class and not an instance of a class, calling self.class
— or self.class.class
if you're acting as an instance, will return Class
attr_accessor
is simply syntactical sugar; it was made because of the mundane chore of having to write those getter/setter methods over and over again. There are cooler problems to solve, like writing our own nadnerb_accessor
in Ruby (though attr_accessor
is implemented in C):
class Ticket
def self.nadnerb_accessor(*names)
names.each do |name|
define_method(name) do
instance_variable_get(:"@#{name}")
end
define_method("#{name}=") do |value|
instance_variable_set(:"@#{name}", value)
end
end
end
nadnerb_accessor :venue, :price
def initialize(venue, price)
self.venue = venue
self.price = price
end
def inspect
"#<Ticket @venue=\"#{@venue}\" @price=\"#{@price}\">"
end
end
ticket = Ticket.new("StackOverflow", "$5")
puts ticket.inspect