Module: Plumb::Attributes

Included in:
Types::Data
Defined in:
lib/plumb/attributes.rb

Defined Under Namespace

Modules: ClassMethods

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#attributesObject (readonly)

Returns the value of attribute attributes.



116
117
118
# File 'lib/plumb/attributes.rb', line 116

def attributes
  @attributes
end

#errorsObject (readonly)

Returns the value of attribute errors.



116
117
118
# File 'lib/plumb/attributes.rb', line 116

def errors
  @errors
end

Class Method Details

.included(base) ⇒ Object

A module that provides a simple way to define a struct-like class with attributes that are type-checked on initialization.

It supports nested attributes:

Or arrays of nested attributes:

Or use struct classes defined separately:

Arrays and other types support composition and helpers. Ex. ‘#default`.

attribute :companies, Types::Array[Company].default([].freeze)

Passing a named struct class AND a block will subclass the struct and extend it with new attributes:

attribute :company, Company do
  attribute :address, String
end

The same works with arrays:

attribute :companies, Types::Array[Company] do
  attribute :address, String
end

Note that this does NOT work with union’d or piped structs.

attribute :company, Company | Person do

## Optional Attributes Using ‘attribute?` allows for optional attributes. If the attribute is not present, it will be set to `Undefined`.

attribute? :company, Company

## Struct Inheritance Structs can inherit from other structs. This is useful for defining a base struct with common attributes.

class BasePerson
  include Plumb::Attributes

  attribute :name, String
end

class Person < BasePerson
  attribute :age, Integer
end

## [] Syntax

The ‘[]` syntax can be used to define a struct in a single line. Like Plumb::Types::Hash, suffixing a key with `?` makes it optional.

Person = Data[name: String, age?: Integer]
person = Person.new(name: 'Jane')

Examples:

class Person
  include Plumb::Attributes

  attribute :name, Types::String
  attribute :age, Types::Integer[18..]
end

person = Person.new(name: 'Jane', age: 20)
person.valid? # => true
person.errors # => {}
person.name # => 'Jane'
class Person
  include Plumb::Attributes

  attribute :friend do
    attribute :name, String
  end
end

person = Person.new(friend: { name: 'John' })
class Person
  include Plumb::Attributes

  attribute :friends, Types::Array do
    atrribute :name, String
  end
end

person = Person.new(friends: [{ name: 'John' }])
class Company
  include Plumb::Attributes
  attribute :name, String
end

class Person
  include Plumb::Attributes

  # Single nested struct
  attribute :company, Company

  # Array of nested structs
  attribute :companies, Types::Array[Company]
end


111
112
113
114
# File 'lib/plumb/attributes.rb', line 111

def self.included(base)
  base.send(:extend, ClassMethods)
  base.define_singleton_method(:__plumb_struct_class__) { base }
end

Instance Method Details

#==(other) ⇒ Object



123
124
125
# File 'lib/plumb/attributes.rb', line 123

def ==(other)
  other.is_a?(self.class) && other.attributes == attributes
end

#deconstructObject



159
# File 'lib/plumb/attributes.rb', line 159

def deconstruct(...) = to_h.values.deconstruct(...)

#deconstruct_keysObject



160
# File 'lib/plumb/attributes.rb', line 160

def deconstruct_keys(...) = to_h.deconstruct_keys(...)

#initialize(attrs = {}) ⇒ Object



118
119
120
121
# File 'lib/plumb/attributes.rb', line 118

def initialize(attrs = {})
  assign_attributes(attrs)
  freeze
end

#inspectObject



136
137
138
139
140
# File 'lib/plumb/attributes.rb', line 136

def inspect
  %(#<#{self.class}:#{object_id} [#{valid? ? 'valid' : 'invalid'}] #{attributes.map do |k, v|
                                                                       [k, v.inspect].join(':')
                                                                     end.join(' ')}>)
end

#to_hHash

Returns:

  • (Hash)


143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/plumb/attributes.rb', line 143

def to_h
  self.class._schema._schema.keys.each.with_object({}) do |key, memo|
    key = key.to_sym
    value = attributes[key]
    val = case value
          when ::Array
            value.map { |v| v.respond_to?(:to_h) ? v.to_h : v }
          when ::NilClass
            nil
          else
            value.respond_to?(:to_h) ? value.to_h : value
          end
    memo[key] = val
  end
end

#valid?Boolean

Returns:

  • (Boolean)


128
# File 'lib/plumb/attributes.rb', line 128

def valid? = !errors || errors.none?

#with(attrs = BLANK_HASH) ⇒ Plumb::Attributes

Parameters:

  • attrs (Hash) (defaults to: BLANK_HASH)

Returns:



132
133
134
# File 'lib/plumb/attributes.rb', line 132

def with(attrs = BLANK_HASH)
  self.class.new(attributes.merge(attrs))
end