Tainbox is a utility gem that can be used to inject attributes into Ruby objects. It is similar to Virtus, but works a bit more sensibly (hopefully) and throws in some additional features.
Consider this code:
class Person
include Tainbox
attribute :name, default: -> { "person_#{age}" }
attribute :age, Integer, default: 20
end
Here are the basic features you get:
person = Person.new(name: 'John', age: '30')
person.attributes # => { :name => "John", :age => 30 }
person.age = 50
person.age # => 50
person.attributes = {}
person.attributes # => { :name => "person_20", :age => 20 }
NOTE: There are two ways to change attributes in bulk. attributes=
replaces missing values
with nils or default values, while patch_attributes
leaves missing attributes untouched.
Observe:
class Person
include Virtus::Model
attribute :age, Integer
end
Person.new(age: 'invalid_integer').age # => "invalid_integer"
Tainbox attributes can be freely overriden:
def name
super.strip
end
def name=(value)
super('Stupid example')
end
Attribute is considered provided if its setter was explicitly invoked via a setter, .new
, or #attributes=
or it has a default value.
class Person
include Tainbox
attribute :name, default: 'John'
attribute :age
end
person = Person.new
person.attribute_provided?(:age) # => false
person.attribute_provided?(:name) # => true
Speaks for itself:
class Person
include Tainbox
attribute :name, reader: false
attribute :age, writer: false
end
All converters return nil if conversion could not be made.
- Integer
- Float
- String
- Symbol
- Time
- Boolean
String converter supports additional options: strip
and downcase
which strip and downcase
input attribute values respectively
Example:
attribute :name, String, strip: true, downcase: true
You can define a custom type converter like so:
# value and options are automatically available in scope
Tainbox.define_converter(MyType) do
# Do whatever you want with value
options[:strict] ? MyType.convert!(value) : MyType.convert(value)
end
class Person
include Tainbox
attribute :name
attribute :age
end
person = Person.new(name: 'John', age: 20)
person.as_json # => { 'name' => 'John', 'age' => 20 }
person.as_json(only: :name) # => { 'name' => 'John' }
person.as_json(except: :name) # => { 'age' => 20 }
If you don't want to pollute your class with tainbox initializer you can do:
class Person
include Tainbox
suppress_tainbox_initializer!
end