μ-attributes (Micro::Attributes)

This gem allows defining read-only attributes, that is, your objects will have only getters to access their attributes data.

Installation

Add this line to your application's Gemfile:

gem 'u-attributes'

And then execute:

$ bundle

Or install it yourself as:

$ gem install u-attributes

Usage

How to require?

# Bundler will do it automatically, but if you desire to do a manual require.
# Use one of the following options:

require 'micro/attributes'

# or

require 'u-attributes'

How to define attributes?


# By default you must to define the class constructor.

class Person
  include Micro::Attributes

  attribute :name
  attribute :age

  def initialize(name: 'John Doe', age:)
    @name, @age = name, age
  end
end

person = Person.new(age: 21)

puts person.name # John Doe
puts person.age  # 21

# By design, the attributes expose only reader methods (getters).
# If you try to call a setter, you will see a NoMethodError.
#
# person.name = 'Rodrigo'
# NoMethodError (undefined method `name=' for #<Person:0x0000... @name="John Doe", @age=21>)

#------------------#
# self.attributes= #
#------------------#

# This protected method is added to make easier the assignment in a constructor.

class Person
  include Micro::Attributes

  attribute :name
  attribute :age

  def initialize(options)
    self.attributes = options
  end
end

person = Person.new('name' => 'John', age: 20)

puts person.name # John
puts person.age  # 20

#--------------#
# #attribute() #
#--------------#
#
# Use the #attribute() method with a valid attribute name to get its value

puts person.attribute(:name) # John
puts person.attribute('age') # 20
puts person.attribute('foo') # nil

#
# If you pass a block, it will be executed only if the attribute is valid.

person.attribute(:name) { |value| puts value } # John
person.attribute('age') { |value| puts value } # 20
person.attribute('foo') { |value| puts value } # !! Nothing happened, because of the attribute not exists.

#--------------#
# #attribute() #
#--------------#
#
# Works like the #attribute() method, but will raise an exception when the attribute not exist.

puts person.attribute!('foo')                   # NameError (undefined attribute `foo)
person.attribute!('foo') { |value| puts value } # NameError (undefined attribute `foo)

How to define multiple attributes?


# Use .attributes with a list of attribute names.

class Person
  include Micro::Attributes

  attributes :name, :age

  def initialize(options)
    self.attributes = options
  end
end

person = Person.new('Serradura', 32)

puts person.name # Serradura
puts person.age  # 32

How to define attributes with a constructor to assign them?

A: Use Micro::Attributes.to_initialize

class Person
  include Micro::Attributes.to_initialize

  attributes :age, name: 'John Doe' # Use a hash to define a default value

  # attribute name: 'John Doe'
  # attribute :age
end

person = Person.new(age: 18)

puts person.name # John Doe
puts person.age  # 18

##############################################
# Assigning new values to get a new instance #
##############################################

#-------------------#
# #with_attribute() #
#-------------------#

another_person = person.with_attribute(:age, 21)

puts another_person.name           # John Doe
puts another_person.age            # 21
puts another_person.equal?(person) # false

#--------------------#
# #with_attributes() #
#--------------------#
#
# Use it to assign multiple attributes

other_person = person.with_attributes(name: 'Serradura', age: 32)

puts other_person.name           # Serradura
puts other_person.age            # 32
puts other_person.equal?(person) # false

# If you pass a value different of a Hash, an ArgumentError will be raised.
#
# Person.new(1)
# ArgumentError (argument must be a Hash)

################
# Inheritance  #
################

class Subclass < Person # Will preserve the parent class attributes
  attribute :foo
end

instance = Subclass.new({})

puts instance.name              # John Doe
puts instance.respond_to?(:age) # true
puts instance.respond_to?(:foo) # true

#---------------------------------#
# .attribute!() or .attributes!() #
#---------------------------------#

# The methods above allow redefining the attributes default data

class AnotherSubclass < Person
  attribute! name: 'Alfa'
end

alfa_person = AnotherSubclass.new({})

p alfa_person.name # "Alfa"
p alfa_person.age  # nil

class SubSubclass < Subclass
  attributes! name: 'Beta', age: 0
end

beta_person = SubSubclass.new({})

p beta_person.name # "Beta"
p beta_person.age  # 0

How to query the attributes?

class Person
  include Micro::Attributes

  attributes :age, name: 'John Doe'

  def initialize(options)
    self.attributes = options
  end
end

#---------------#
# .attributes() #
#---------------#

p Person.attributes # ["name", "age"]

#---------------#
# .attribute?() #
#---------------#

puts Person.attribute?(:name)  # true
puts Person.attribute?('name') # true
puts Person.attribute?('foo') # false
puts Person.attribute?(:foo)  # false

# ---

person = Person.new(age: 20)

#---------------#
# #attribute?() #
#---------------#

puts person.attribute?(:name)  # true
puts person.attribute?('name') # true
puts person.attribute?('foo') # false
puts person.attribute?(:foo)  # false

#---------------#
# #attributes() #
#---------------#

p person.attributes                   # {"age"=>20, "name"=>"John Doe"}
p Person.new(name: 'John').attributes # {"age"=>nil, "name"=>"John"}

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake test to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/serradura/u-attributes. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

License

The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the Micro::Attributes project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.