Class: Dry::Struct

Inherits:
Object
  • Object
show all
Extended by:
Core::Extensions, ClassInterface
Includes:
Core::Constants
Defined in:
lib/dry/struct.rb,
lib/dry/struct/sum.rb,
lib/dry/struct/value.rb,
lib/dry/struct/errors.rb,
lib/dry/struct/hashify.rb,
lib/dry/struct/version.rb,
lib/dry/struct/compiler.rb,
lib/dry/struct/constructor.rb,
lib/dry/struct/struct_builder.rb,
lib/dry/struct/class_interface.rb,
lib/dry/struct/extensions/pretty_print.rb

Overview

Typed Struct with virtus-like DSL for defining schema.

### Differences between dry-struct and virtus

Struct look somewhat similar to [Virtus][] but there are few significant differences:

  • Structs don’t provide attribute writers and are meant to be used as “data objects” exclusively.

  • Handling of attribute values is provided by standalone type objects from [‘dry-types`][].

  • Handling of attribute hashes is provided by standalone hash schemas from [‘dry-types`][].

  • Struct classes quack like [‘dry-types`][], which means you can use them in hash schemas, as array members or sum them

Struct class can specify a constructor type, which uses [hash schemas][] to handle attributes in ‘.new` method.

[‘dry-types`]: github.com/dry-rb/dry-types [Virtus]: github.com/solnic/virtus [hash schemas]: dry-rb.org/gems/dry-types/hash-schemas

Examples:

require 'dry-struct'

module Types
  include Dry.Types()
end

class Book < Dry::Struct
  attribute :title, Types::String
  attribute :subtitle, Types::String.optional
end

rom_n_roda = Book.new(
  title: 'Web Development with ROM and Roda',
  subtitle: nil
)
rom_n_roda.title #=> 'Web Development with ROM and Roda'
rom_n_roda.subtitle #=> nil

refactoring = Book.new(
  title: 'Refactoring',
  subtitle: 'Improving the Design of Existing Code'
)
refactoring.title #=> 'Refactoring'
refactoring.subtitle #=> 'Improving the Design of Existing Code'

Direct Known Subclasses

Value

Defined Under Namespace

Modules: ClassInterface, Hashify Classes: Compiler, Constructor, MissingAttributeError, RecycledStructError, RepeatedAttributeError, StructBuilder, Sum, Value

Constant Summary collapse

Error =

Raised when given input doesn’t conform schema and constructor type

Class.new(TypeError)
VERSION =
"1.6.0"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ClassInterface

===, abstract, attribute, attribute?, attribute_names, attributes_from, call_safe, call_unsafe, constrained?, constructor, default?, failure, has_attribute?, inherited, load, meta, optional?, primitive, result, success, to_ast, to_proc, transform_keys, transform_types, try, try_struct, |

Constructor Details

#initialize(attributes) ⇒ Struct

Returns a new instance of Struct.

Parameters:

  • attributes (Hash, #each)


126
127
128
# File 'lib/dry/struct.rb', line 126

def initialize(attributes)
  @attributes = attributes
end

Instance Attribute Details

#attributesObject Also known as: __attributes__

Returns the value of attribute attributes.



122
123
124
# File 'lib/dry/struct.rb', line 122

def attributes
  @attributes
end

Class Method Details

.loaderObject



94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/dry/struct.rb', line 94

def loader
  @loader ||= ::Zeitwerk::Loader.new.tap do |loader|
    root = ::File.expand_path("..", __dir__)
    loader.tag = "dry-struct"
    loader.inflector = ::Zeitwerk::GemInflector.new("#{root}/dry-struct.rb")
    loader.push_dir(root)
    loader.ignore(
      "#{root}/dry-struct.rb",
      "#{root}/dry/struct/{class_interface,errors,extensions,printer,value,version}.rb",
      "#{root}/dry/struct/extensions"
    )
  end
end

Instance Method Details

#[](name) ⇒ Object

Retrieves value of previously defined attribute by its’ ‘name`

Examples:

class Book < Dry::Struct
  attribute :title, Types::String
  attribute :subtitle, Types::String.optional
end

rom_n_roda = Book.new(
  title: 'Web Development with ROM and Roda',
  subtitle: nil
)
rom_n_roda[:title] #=> 'Web Development with ROM and Roda'
rom_n_roda[:subtitle] #=> nil

Parameters:

  • name (String)

Returns:

  • (Object)


147
148
149
# File 'lib/dry/struct.rb', line 147

def [](name)
  @attributes.fetch(name) { raise MissingAttributeError, name }
end

#deconstruct_keys(_keys) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Pattern matching support



218
219
220
# File 'lib/dry/struct.rb', line 218

def deconstruct_keys(_keys)
  attributes
end

#inspectString

Returns:

  • (String)


209
210
211
212
213
# File 'lib/dry/struct.rb', line 209

def inspect
  klass = self.class
  attrs = klass.attribute_names.map { |key| " #{key}=#{@attributes[key].inspect}" }.join
  "#<#{klass.name || klass.inspect}#{attrs}>"
end

#new(changeset) ⇒ Struct Also known as: __new__

Create a copy of Dry::Struct with overriden attributes

Examples:

class Book < Dry::Struct
  attribute :title, Types::String
  attribute :subtitle, Types::String.optional
end

rom_n_roda = Book.new(
  title: 'Web Development with ROM and Roda',
  subtitle: '2nd edition'
)
  #=> #<Book title="Web Development with ROM and Roda" subtitle="2nd edition">

rom_n_roda.new(subtitle: '3rd edition')
  #=> #<Book title="Web Development with ROM and Roda" subtitle="3rd edition">

Parameters:

  • changeset (Hash{Symbol => Object})

Returns:



196
197
198
199
200
201
202
203
204
205
# File 'lib/dry/struct.rb', line 196

def new(changeset)
  new_attributes = self.class.schema.apply(
    changeset,
    skip_missing: true,
    resolve_defaults: false
  )
  self.class.load(__attributes__.merge(new_attributes))
rescue Types::SchemaError, Types::MissingKeyError, Types::UnknownKeysError => e
  raise Error, "[#{self}.new] #{e}"
end

#pretty_print(pp) ⇒ Object



7
8
9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/dry/struct/extensions/pretty_print.rb', line 7

def pretty_print(pp)
  klass = self.class
  pp.group(1, "#<#{klass.name || klass.inspect}", ">") do
    pp.seplist(@attributes.keys, proc { pp.text "," }) do |column_name|
      column_value = @attributes[column_name]
      pp.breakable " "
      pp.group(1) do
        pp.text column_name.to_s
        pp.text "="
        pp.pp column_value
      end
    end
  end
end

#schemaDry::Types::Hash::Schema

Types::Hash::Schema subclass with specific behaviour defined for

Returns:

  • (Dry::Types::Hash::Schema)


115
# File 'lib/dry/struct.rb', line 115

defines :schema

#to_hHash{Symbol => Object} Also known as: to_hash

Converts the Dry::Struct to a hash with keys representing each attribute (as symbols) and their corresponding values

Examples:

class Book < Dry::Struct
  attribute :title, Types::String
  attribute :subtitle, Types::String.optional
end

rom_n_roda = Book.new(
  title: 'Web Development with ROM and Roda',
  subtitle: nil
)
rom_n_roda.to_hash
  #=> {title: 'Web Development with ROM and Roda', subtitle: nil}

Returns:

  • (Hash{Symbol => Object})


168
169
170
171
172
# File 'lib/dry/struct.rb', line 168

def to_h
  self.class.schema.each_with_object({}) do |key, result|
    result[key.name] = Hashify[self[key.name]] if attributes.key?(key.name)
  end
end