DEV Community

hungle00
hungle00

Posted on

Ruby - DIY accessor methods

1. Ruby accessor methods

Ruby does not allow instance variables to be accessed outside of methods for that object.

class Person def initialize(name) @name = name @age = 10 end end p = Person.new('steve') p.name # => undefined method `name=' for #<Person ..> 
Enter fullscreen mode Exit fullscreen mode

This design ensures OOP encapsulation - an object’s data is protected from the outside world.

In some languages like Java, to access private instance variables, you must define getter/setter methods for each attribute. But in Ruby, you can generate getter/setter methods by using one of the methods in the Module#attr_* family.

class Person attr_reader :name, :age # getter  attr_writer :name, :age # setter # attr_accessor :name, :age # getter + setter # other code .... end p = Person.new('steve') p.name # => steve p.age = 20 p.age # => 20 
Enter fullscreen mode Exit fullscreen mode

It just takes one or two lines for all of the attributes. These methods are called Class Macros which are class methods only used when in a class definition.

2. DIY accessor methods

There are advanced ways to access instance variables, like instance_variable_get, instance_eval.
For example:

p = Person.new('steve') p.instance_variable_get(:@name) p.instance_eval { @name } 
Enter fullscreen mode Exit fullscreen mode

Using some metaprogramming techniques, we can build attribute accessor methods by myself.

module GetterSetter def attr_getter(*attributes) attributes.each do |attribute| define_method attribute do instance_variable_get("@#{attribute}") end end end def attr_setter(*attributes) attributes.each do |attribute| define_method "#{attribute}=" do |value| instance_variable_set("@#{attribute}", value) end end end def attr_getter_and_setter(*attributes) attr_getter(*attributes) attr_setter(*attributes) end end 
Enter fullscreen mode Exit fullscreen mode

For simplicity, I define getter/setter in separated module and include in Person class.

class Person extend GetterSetter def initialize(name) @name = name @age = 10 end attr_getter :name, :age attr_setter :name, :age # or  # attr_getter_and_setter :name, :age end p = Person.new('Luke') p.name = 'anakin' p.name # => anakin 
Enter fullscreen mode Exit fullscreen mode

Summary

Class macros are one of Ruby's magic methods that help developers get rid of a lot of tedious, boilerplate methods. In rails, class macros are used a lot, for associations ( has_many, belongs_to ), validation, ...

You can learn more about Ruby class macros or other metaprogramming techniques in the Metaprogramming Ruby book ( https://pragprog.com/titles/ppmetr2/metaprogramming-ruby-2/)

Top comments (0)