Need help with attrio?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

jetrockets
195 Stars 9 Forks MIT License 122 Commits 6 Opened issues

Description

Attributes for plain old Ruby objects. No dependencies, only simplicity and clearness.

Services available

!
?

Need anything else?

Contributors list

Build Status Code Climate Coverage Status Dependency Status Gem Version

Attrio

Attributes for plain Ruby objects. The goal is to provide an ability to define attributes for your models without reinventing the wheel all over again. Attrio doesn't have any third-party dependencies like Virtus or ActiveAttr and does not redefine any methods inside your class, unless you want it to.

Installation

Add this line to your application's Gemfile:

gem 'attrio'

And then execute:

$ bundle

Or install it yourself as:

$ gem install attrio

Usage

Include Attrio into your class and then use

#define_attributes
block to declare you attributes.
class User
  include Attrio

define_attributes do attr :name, String attr :age, Integer attr :birthday, DateTime end end

Accessing attributes

By default Attrio defines

#attributes
accessor which contains
Hash
with attributes names as keys and instances of
Attrio::Attribute
as values. Each instance of
Attrio::Attribute
contains following information: * type * writer method name * writer method visibility * reader method name * reader method visibility * instance variable name * additional options
user = User.new
user.attributes
# => {
#   :name => #<:attribute:0x007fc44e8ca680>, @name="name", @type=String, @options={}, @writer_method_name="name=", @writer_visibility=:public, @instance_variable_name="@name", @reader_method_name="name", @reader_visibility=:public>,
#   :age => #<:attribute:0x007fc44e8d4c98>, @name="age", @type=Attrio::Types::Integer, @options={}, @writer_method_name="age=", @writer_visibility=:public, @instance_variable_name="@age", @reader_method_name="age", @reader_visibility=:public>,
#   :birthday = >#<:attribute:0x007fc44e8e2e38>, @name="birthday", @type=Attrio::Types::DateTime, @options={}, @writer_method_name="birthday=", @writer_visibility=:public, @instance_variable_name="@birthday", @reader_method_name="birthday", @reader_visibility=:public>
# }
user.attributes.keys
# => [:name, :age, :birthday]

Attributes can be filtered.

user.attributes([:name, :age, :not_existing_attribute]).keys
# => [:name, :age]

Accessor name can be easily overridden by passing

:as
option to
define_attributes
block.
class User
  include Attrio

define_attributes :as => 'api_attributes' do attr :name, String attr :age, Integer attr :birthday, DateTime end

define_attributes :as => 'settings' do attr :receives_notifications, Boolean, :default => true end

end

user = User.new
user.api_attributes # => {...}

Default values

Attrio supports all the ways to setup default values that Virtus has.

class Page
  include Attrio

define_attributes do attr :title, String

# default from a singleton value (integer in this case)
attr :views, Integer, :default =&gt; 0

# default from a singleton value (boolean in this case)
attr :published, Boolean, :default =&gt; false

# default from a callable object (proc in this case)
attr :slug, String, :default =&gt; lambda { |page, attribute| page.title.present? ? page.title.downcase.gsub(' ', '-') : nil }

# default from a method name as symbol
attr :editor_title, String,  :default =&gt; :default_editor_title

end

def initialize(attributes = {}) self.attributes = attributes end

def attributes=(attributes = {}) attributes.each do |attr,value| self.send("#{attr}=", value) if self.respond_to?("#{attr}=") end end

def default_editor_title if self.published? title else title.present? ? "UNPUBLISHED: #{title}" : "UNPUBLISHED" end end end

You can does your attribute still has default value or not.

p = Page.new
=> #
p.attributes[:editor_title].default?
=> true
p.editor_title = 'PUBLISHED'
=> "PUBLISHED"
p.attributes[:editor_title].default?
=> false

Embed Value

You can embed values in Attrio just like you do it in Virtus.

module MassAssignment
  def initialize(attributes = {})
    self.attributes = attributes
  end

def attributes=(attributes = {}) attributes.each do |attr,value| self.send("#{attr}=", value) if self.respond_to?("#{attr}=") end end end

class City include Attrio include MassAssignment

define_attributes do attr :name, String end end

class Address include Attrio include MassAssignment

define_attributes do attr :street, String attr :zipcode, String attr :city, City end end

class User include Attrio include MassAssignment

define_attributes do attr :name, String attr :address, Address end end

user = User.new( :address => { :street => 'Sklizkova 6A', :zipcode => '170000', :city => { :name => 'Tver' } } ) user.address.street

=> 'Sklizkova 6A'

user.address.zipcode

=> '170000'

user.address.city.name

=> 'Tver'

Methods visibility

Don't want your accessors to be public? Visibility can be overridden easily.

class User
  include Attrio

define_attributes do attr :name, String, :writer => :protected attr :secret_rating, Integer, :reader => :private end end

Types

Any Ruby class can be passed as type to Attrio. If this class responds to

typecast
and
typecasted?
methods then they will be called, else
new
will be called.
class Klass
  include Attrio

define_attributes do attr :custom_attribute, CustomClass end end

Built-in Types

Boolean

By default boolean typecasts 'yes', '1', 1, 'true' as

TrueClass
and all other values as
FalseClass
, but you easily modify this behaviour.
class Klass
  include Attrio

define_attributes do attr :boolean_attribute, Boolean

attr :custom_boolean_attribute, Boolean, :yes =&gt; ['ja', '1', 1]
# attr :custom_boolean_attribute, Boolean, :yes_values =&gt; ['ja', '1', 1]
# attr :custom_boolean_attribute, Boolean, :no =&gt; ['nein', '0', 0]
# attr :custom_boolean_attribute, Boolean, :no_values =&gt; ['nein', '0', 0]

end end

Date, Time and DateTime

These three class have similar behaviour and options. By passing

:format
option you can setup how
strftime
method will try to parse your string.
class Klass
  include Attrio

define_attributes do attr :date_attribute, Date attr :time_attribute, Time attr :date_time_attribute, DateTime

attr :custom_date_time_attribute, DateTime, :format =&gt; '%m/%d/%y-%H:%M:%S-%z'

end end

Float

Attribute will be typecasted using

to_f
method.
class Klass
  include Attrio

define_attributes do attr :float_attribute, Float end end

Integer

Attribute will be typecasted using

to_i
method.

Optional

:base
parameter can be passed, during the typecast attribute will be assumed to be in specified base and will always be translated to decimal base.
class Klass
  include Attrio

define_attributes do attr :integer_attribute, Integer attr :custom_integer_attribute, Integer, :base => 2 end end

Symbol

Attribute will be typecasted using

to_sym
method.

If Optional

:underscore
parameter is passed, then attribute value will be downcased and underscored before calling
to_sym
.
class Klass
  include Attrio

define_attributes do attr :symbol_attribute, Symbol attr :custom_symbol_attribute, Symbol, :underscore => true end end

Array

Arrays are designed to automatically handle collections of objects (that also can be typecasted)

If value that should be typecasted responds to

split
, then this method is called with default (or overriden) attributes, else
Array
is wrapped on value. You can easily handle types and options of collection elements.
class Klass
  include Attrio

define_attributes do attr :array_attribute, Array attr :custom_array_attribute, Array, :split => ', ', :element => { :type => Date, :options => { :format => '%m/%d/%y' } } end end

Inspect

Attrio adds its own

#inspect
method when included to the class. This overridden method prints object attributes in easy to read manner. To disable this feature pass
:inspect => false
to
define_arguments
block.
class Klass
  include Attrio

define_attributes :inspect => false do attr :attribute, String end end

Note on Patches / Pull Requests

  • Fork the project.
  • Make your feature addition or bug fix.
  • Add tests for it. This is important so I don't break it in a future version unintentionally.
  • Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
  • Send me a pull request. Bonus points for topic branches.

Credits

JetRockets

Webmaster is maintained by JetRockets.

Contributors:

License

It is free software, and may be redistributed under the terms specified in the LICENSE file.

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.