Class: Evil::Struct

Inherits:
Object
  • Object
show all
Extended by:
Dry::Initializer::Mixin
Defined in:
lib/evil/struct.rb

Overview

Nested structure with type constraints, based on the ‘dry-initializer` DSL

Defined Under Namespace

Modules: Utils Classes: Attributes

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.attributes(options) ⇒ self

Shares options between definitions made inside the block

Examples:

attributes optional: true do
  attribute :foo
  attribute :bar
end

Returns:

  • (self)

    itself



48
49
50
51
# File 'lib/evil/struct.rb', line 48

def attributes(**options, &block)
  Attributes.call(self, options, &block)
  self
end

.list_of_attributesArray<Symbol>

Returns the list of defined attributes

Returns:

  • (Array<Symbol>)


57
58
59
# File 'lib/evil/struct.rb', line 57

def list_of_attributes
  @list_of_attributes ||= []
end

.new(value = {}) ⇒ Evil::Struct Also known as: call, [], load

Builds a struct from value that respond to ‘to_h` or `to_hash`

Parameters:

Returns:



20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/evil/struct.rb', line 20

def new(value = {})
  value if value.instance_of? self.class

  hash = value           if value.is_a? Hash
  hash ||= value.to_h    if value.respond_to? :to_h
  hash ||= value.to_hash if value.respond_to? :to_hash

  hash_with_symbolic_keys = hash.each_with_object({}) do |(key, val), obj|
    obj[key.to_sym] = val
  end
  super hash_with_symbolic_keys
end

.option(name, type = nil, as: nil, **opts) ⇒ self Also known as: attribute, param

Declares the attribute

Parameters:

  • name (#to_sym)

    The name of the key

  • type (#call) (defaults to: nil)

    (nil) The type constraint

  • options (Hash)

    a customizable set of options

Returns:

  • (self)


75
76
77
78
# File 'lib/evil/struct.rb', line 75

def option(name, type = nil, as: nil, **opts)
  super.tap { list_of_attributes << (as || name).to_sym }
  self
end

Instance Method Details

#==(other) ⇒ Boolean

Checks an equality to other object that respond to ‘to_h` or `to_hash`

Parameters:

  • other (Object)

Returns:

  • (Boolean)


95
96
97
98
99
100
101
102
103
# File 'lib/evil/struct.rb', line 95

def ==(other)
  if other&.respond_to?(:to_h)
    to_h == other.to_h
  elsif other.respond_to?(:to_hash)
    to_h == other.to_hash
  else
    false
  end
end

#merge(other) ⇒ self.class

Shallowly merges other object to the current struct

Examples:

class User < Evil::Struct
  attribute :name
  attribute :age
end
joe_at_3 = User.new(name: "Joe", age: 3)

joe_at_4 = joe_at_3.merge(age: 4)
joe_at_4.name # => "Joe"
joe_at_4.age  # => 4

Parameters:

Returns:

  • (self.class)

    new instance of the current class



159
160
161
# File 'lib/evil/struct.rb', line 159

def merge(other)
  self.class[Utils.merge(to_h, other)]
end

#merge_deeply(other) ⇒ self.class Also known as: deep_merge

Deeply merges other object to the current struct

It iterates through hashes and objects responding to ‘to_h` and `to_hash`. The iteration stops when any non-hash value reached.

Examples:

class User < Evil::Struct
  attribute :info
  attribute :meta
end
user = User.new info: { names: [{ first: "Joe", last: "Doe" }], age: 33 },
                meta: { type:  :admin }

user.merge info: { names: [{ first: "John" }] }, meta: { "role" => :cto }
user.to_h # => {
          #      info: { names: [{ first: "John" }], age: 33 },
          #      meta: { type: :admin, role: :cto }
          #    }

Parameters:

Returns:

  • (self.class)

    new instance of the current class



187
188
189
# File 'lib/evil/struct.rb', line 187

def merge_deeply(other)
  self.class[Utils.merge_deeply(self, other)]
end

#to_hHash Also known as: to_hash, dump

Converts nested structure to hash

Makes conversion through nested hashes, arrays, enumerables, as well as trhough values that respond to ‘to_a`, `to_h`, and `to_hash`. Doesn’t convert ‘nil`.

Returns:

  • (Hash)


116
117
118
119
120
121
# File 'lib/evil/struct.rb', line 116

def to_h
  self.class.list_of_attributes.each_with_object({}) do |key, hash|
    val = instance_variable_get :"@#{key}"
    hash[key] = Utils.hashify(val) unless val == Dry::Initializer::UNDEFINED
  end
end