dry-struct 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0b2abda38b30796edc16f515274eb6c0be35a528
4
- data.tar.gz: 0114e855f8892fcfb1598410da854f52e61188ae
3
+ metadata.gz: 0cc9fef4b32f2b57bac889a7f5ca759795b650dd
4
+ data.tar.gz: be8ff9b280bcc8d0afdccf28d39453b7060e13d3
5
5
  SHA512:
6
- metadata.gz: eb01e9ed8ec7a914957c385733e0ea1894621309721527e5de11c1855d36fc2f0b615d5387474947cb65da30b52b70b5cc33701170ffaa987a2a53481352731c
7
- data.tar.gz: e1403ea9f6f014e7d0fb31f64019dc179f87175c9fbe0afcb42551ec6b7cb5b09a9b73df5b7d4d33702a5d8684a7213648f35903f906b0a5628d84b2553ed37f
6
+ metadata.gz: f8c76b9683ad51451060a3c388741598aedcac78946b0f979c8928fef1a3e6f4300c211438f3d3ca6490c23525730d051ffb7c2a808fd5e1b322474e91b20e9a
7
+ data.tar.gz: 0d8dc1bc47204f422ee104d60ee732e7bb276e3441ec255303f3a794f2718be0eb63bea2beda822c08a40a1a04a864d097171c4becaede57d7ffa701794a17fd
@@ -5,16 +5,21 @@ bundler_args: --without benchmarks tools
5
5
  script:
6
6
  - bundle exec rake spec
7
7
  after_success:
8
- - '[ "$TRAVIS_RUBY_VERSION" = "2.3.1" ] && [ "$TRAVIS_BRANCH" = "master" ] && bundle exec codeclimate-test-reporter'
8
+ - '[ -d coverage ] && bundle exec codeclimate-test-reporter'
9
9
  rvm:
10
10
  - 2.1.10
11
- - 2.2.5
12
- - 2.3.1
11
+ - 2.2.7
12
+ - 2.3.3
13
+ - 2.4.1
13
14
  - rbx-3
14
- - jruby-9.1.5.0
15
+ - jruby-9.1.8.0
15
16
  env:
16
17
  global:
18
+ - COVERAGE=true
17
19
  - JRUBY_OPTS='--dev -J-Xmx1024M'
20
+ matrix:
21
+ allow_failures:
22
+ - rvm: rbx-3
18
23
  notifications:
19
24
  email: false
20
25
  webhooks:
@@ -0,0 +1,4 @@
1
+ --title 'dry-struct'
2
+ --markup markdown
3
+ --readme README.md
4
+ lib/**/*.rb
@@ -1,9 +1,28 @@
1
+ master
2
+
3
+ ## Added
4
+
5
+ * `Dry::Struct#new` method to return new instance with applied changeset (Kukunin)
6
+
7
+ ## Fixed
8
+
9
+ * `.[]` and `.call` does not coerce subclass to superclass anymore (Kukunin)
10
+ * Raise ArgumentError when attribute type is a string and no value provided is for `new` (GustavoCaso)
11
+
12
+ ## Changed
13
+
14
+ * `.new` without arguments doesn't use nil as an input for non-default types anymore (flash-gordon)
15
+
16
+ [Compare v0.2.1...master](https://github.com/dry-rb/dry-struct/compare/v0.2.1...master)
17
+
1
18
  # v0.2.1 2017-02-27
2
19
 
3
20
  ## Fixed
4
21
 
5
22
  * Fixed `Dry::Struct::Value` which appeared to be broken in the last release (flash-gordon)
6
23
 
24
+ [Compare v0.2.0...v0.2.1](https://github.com/dry-rb/dry-struct/compare/v0.2.0...v0.2.1)
25
+
7
26
  # v0.2.0 2016-02-26
8
27
 
9
28
  ## Changed
data/Rakefile CHANGED
@@ -4,3 +4,7 @@ require 'rspec/core/rake_task'
4
4
  RSpec::Core::RakeTask.new(:spec)
5
5
 
6
6
  task :default => :spec
7
+
8
+ require 'yard'
9
+ require 'yard/rake/yardoc_task'
10
+ YARD::Rake::YardocTask.new(:doc)
@@ -1,5 +1,3 @@
1
- # coding: utf-8
2
-
3
1
  lib = File.expand_path('../lib', __FILE__)
4
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
3
  require 'dry/struct/version'
@@ -31,9 +29,11 @@ Gem::Specification.new do |spec|
31
29
  spec.add_runtime_dependency 'dry-equalizer', '~> 0.2'
32
30
  spec.add_runtime_dependency 'dry-configurable', '~> 0.1'
33
31
  spec.add_runtime_dependency 'dry-types', '~> 0.9', '>= 0.9.0'
32
+ spec.add_runtime_dependency 'dry-core', '~> 0.3'
34
33
  spec.add_runtime_dependency 'ice_nine', '~> 0.11'
35
34
 
36
35
  spec.add_development_dependency 'bundler', '~> 1.6'
37
36
  spec.add_development_dependency 'rake', '~> 11.0'
38
37
  spec.add_development_dependency 'rspec', '~> 3.3'
38
+ spec.add_development_dependency 'yard', '~> 0.9.5'
39
39
  end
@@ -6,25 +6,230 @@ require 'dry/struct/class_interface'
6
6
  require 'dry/struct/hashify'
7
7
 
8
8
  module Dry
9
+ # Typed {Struct} with virtus-like DSL for defining schema.
10
+ #
11
+ # ### Differences between dry-struct and virtus
12
+ #
13
+ # {Struct} look somewhat similar to [Virtus][] but there are few significant differences:
14
+ #
15
+ # * {Struct}s don't provide attribute writers and are meant to be used
16
+ # as "data objects" exclusively.
17
+ # * Handling of attribute values is provided by standalone type objects from
18
+ # [`dry-types`][].
19
+ # * Handling of attribute hashes is provided by standalone hash schemas from
20
+ # [`dry-types`][], which means there are different types of constructors in
21
+ # {Struct} (see {Dry::Struct::ClassInterface#constructor_type})
22
+ # * Struct classes quack like [`dry-types`][], which means you can use them
23
+ # in hash schemas, as array members or sum them
24
+ #
25
+ # {Struct} class can specify a constructor type, which uses [hash schemas][]
26
+ # to handle attributes in `.new` method.
27
+ # See {ClassInterface#new} for constructor types descriptions and examples.
28
+ #
29
+ # [`dry-types`]: https://github.com/dry-rb/dry-types
30
+ # [Virtus]: https://github.com/solnic/virtus
31
+ # [hash schemas]: http://dry-rb.org/gems/dry-types/hash-schemas
32
+ #
33
+ # @example
34
+ # require 'dry-struct'
35
+ #
36
+ # module Types
37
+ # include Dry::Types.module
38
+ # end
39
+ #
40
+ # class Book < Dry::Struct
41
+ # attribute :title, Types::Strict::String
42
+ # attribute :subtitle, Types::Strict::String.optional
43
+ # end
44
+ #
45
+ # rom_n_roda = Book.new(
46
+ # title: 'Web Development with ROM and Roda',
47
+ # subtitle: nil
48
+ # )
49
+ # rom_n_roda.title #=> 'Web Development with ROM and Roda'
50
+ # rom_n_roda.subtitle #=> nil
51
+ #
52
+ # refactoring = Book.new(
53
+ # title: 'Refactoring',
54
+ # subtitle: 'Improving the Design of Existing Code'
55
+ # )
56
+ # refactoring.title #=> 'Refactoring'
57
+ # refactoring.subtitle #=> 'Improving the Design of Existing Code'
9
58
  class Struct
10
59
  extend ClassInterface
11
60
 
12
- constructor_type(:permissive)
61
+ # {Dry::Types::Hash} subclass with specific behaviour defined for
62
+ # @return [Dry::Types::Hash]
63
+ # @see #constructor_type
64
+ defines :input
65
+ input Types['coercible.hash']
13
66
 
67
+ # Sets or retrieves {#constructor} type as a symbol
68
+ #
69
+ # @note All examples below assume that you have defined {Struct} with
70
+ # following attributes and explicitly call only {#constructor_type}:
71
+ #
72
+ # ```ruby
73
+ # class User < Dry::Struct
74
+ # attribute :name, Types::Strict::String.default('John Doe')
75
+ # attribute :age, Types::Strict::Int
76
+ # end
77
+ # ```
78
+ #
79
+ # ### Common constructor types include:
80
+ #
81
+ # * `:permissive` - the default constructor type, useful for defining
82
+ # {Struct}s that are instantiated using data from the database
83
+ # (i.e. results of a database query), where you expect *all defined
84
+ # attributes to be present* and it's OK to ignore other keys
85
+ # (i.e. keys used for joining, that are not relevant from your domain
86
+ # {Struct}s point of view). Default values **are not used** otherwise
87
+ # you wouldn't notice missing data.
88
+ # * `:schema` - missing keys will result in setting them using default
89
+ # values, unexpected keys will be ignored.
90
+ # * `:strict` - useful when you *do not expect keys other than the ones
91
+ # you specified as attributes* in the input hash
92
+ # * `:strict_with_defaults` - same as `:strict` but you are OK that some
93
+ # values may be nil and you want defaults to be set
94
+ #
95
+ # To feel the difference between constructor types, look into examples.
96
+ # Each of them provide the same attributes' definitions,
97
+ # different constructor type, and 4 cases of given input:
98
+ #
99
+ # 1. Input omits a key for a value that does not have a default
100
+ # 2. Input omits a key for a value that has a default
101
+ # 3. Input contains nil for a value that specifies a default
102
+ # 4. Input includes a key that was not specified in the schema
103
+ #
104
+ # @note Don’t use `:weak` and `:symbolized` as {#constructor_type},
105
+ # and instead use [`dry-validation`][] to process and validate
106
+ # attributes, otherwise your struct will behave as a data validator
107
+ # which raises exceptions on invalid input (assuming your attributes
108
+ # types are strict)
109
+ # [`dry-validation`]: https://github.com/dry-rb/dry-validation
110
+ #
111
+ # @example `:permissive` constructor
112
+ # class User < Dry::Struct
113
+ # constructor_type :permissive
114
+ # end
115
+ #
116
+ # User.new(name: "Jane")
117
+ # #=> Dry::Struct::Error: [User.new] :age is missing in Hash input
118
+ # User.new(age: 31)
119
+ # #=> Dry::Struct::Error: [User.new] :name is missing in Hash input
120
+ # User.new(name: nil, age: 31)
121
+ # #=> #<User name="John Doe" age=31>
122
+ # User.new(name: "Jane", age: 31, unexpected: "attribute")
123
+ # #=> #<User name="Jane" age=31>
124
+ #
125
+ # @example `:schema` constructor
126
+ # class User < Dry::Struct
127
+ # constructor_type :schema
128
+ # end
129
+ #
130
+ # User.new(name: "Jane") #=> #<User name="Jane" age=nil>
131
+ # User.new(age: 31) #=> #<User name="John Doe" age=31>
132
+ # User.new(name: nil, age: 31) #=> #<User name="John Doe" age=31>
133
+ # User.new(name: "Jane", age: 31, unexpected: "attribute")
134
+ # #=> #<User name="Jane" age=31>
135
+ #
136
+ # @example `:strict` constructor
137
+ # class User < Dry::Struct
138
+ # constructor_type :strict
139
+ # end
140
+ #
141
+ # User.new(name: "Jane")
142
+ # #=> Dry::Struct::Error: [User.new] :age is missing in Hash input
143
+ # User.new(age: 31)
144
+ # #=> Dry::Struct::Error: [User.new] :name is missing in Hash input
145
+ # User.new(name: nil, age: 31)
146
+ # #=> Dry::Struct::Error: [User.new] nil (NilClass) has invalid type for :name
147
+ # User.new(name: "Jane", age: 31, unexpected: "attribute")
148
+ # #=> Dry::Struct::Error: [User.new] unexpected keys [:unexpected] in Hash input
149
+ #
150
+ # @example `:strict_with_defaults` constructor
151
+ # class User < Dry::Struct
152
+ # constructor_type :strict_with_defaults
153
+ # end
154
+ #
155
+ # User.new(name: "Jane")
156
+ # #=> Dry::Struct::Error: [User.new] :age is missing in Hash input
157
+ # User.new(age: 31)
158
+ # #=> #<User name="John Doe" age=31>
159
+ # User.new(name: nil, age: 31)
160
+ # #=> Dry::Struct::Error: [User.new] nil (NilClass) has invalid type for :name
161
+ # User.new(name: "Jane", age: 31, unexpected: "attribute")
162
+ # #=> Dry::Struct::Error: [User.new] unexpected keys [:unexpected] in Hash input
163
+ #
164
+ # @see http://dry-rb.org/gems/dry-types/hash-schemas
165
+ #
166
+ # @overload constructor_type(type)
167
+ # Sets the constructor type for {Struct}
168
+ # @param [Symbol] type one of constructor types, see above
169
+ # @return [Symbol]
170
+ #
171
+ # @overload constructor_type
172
+ # Returns the constructor type for {Struct}
173
+ # @return [Symbol] (:strict)
174
+ defines :constructor_type
175
+ constructor_type :permissive
176
+
177
+ # @return [Dry::Equalizer]
178
+ defines :equalizer
179
+
180
+ # @param [Hash, #each] attributes
14
181
  def initialize(attributes)
15
182
  attributes.each { |key, value| instance_variable_set("@#{key}", value) }
16
183
  end
17
184
 
185
+ # Retrieves value of previously defined attribute by its' `name`
186
+ #
187
+ # @param [String] name
188
+ # @return [Object]
189
+ #
190
+ # @example
191
+ # class Book < Dry::Struct
192
+ # attribute :title, Types::Strict::String
193
+ # attribute :subtitle, Types::Strict::String.optional
194
+ # end
195
+ #
196
+ # rom_n_roda = Book.new(
197
+ # title: 'Web Development with ROM and Roda',
198
+ # subtitle: nil
199
+ # )
200
+ # rom_n_roda[:title] #=> 'Web Development with ROM and Roda'
201
+ # rom_n_roda[:subtitle] #=> nil
18
202
  def [](name)
19
203
  public_send(name)
20
204
  end
21
205
 
206
+ # Converts the {Dry::Struct} to a hash with keys representing
207
+ # each attribute (as symbols) and their corresponding values
208
+ #
209
+ # @return [Hash{Symbol => Object}]
210
+ #
211
+ # @example
212
+ # class Book < Dry::Struct
213
+ # attribute :title, Types::Strict::String
214
+ # attribute :subtitle, Types::Strict::String.optional
215
+ # end
216
+ #
217
+ # rom_n_roda = Book.new(
218
+ # title: 'Web Development with ROM and Roda',
219
+ # subtitle: nil
220
+ # )
221
+ # rom_n_roda.to_hash
222
+ # #=> {title: 'Web Development with ROM and Roda', subtitle: nil}
22
223
  def to_hash
23
224
  self.class.schema.keys.each_with_object({}) do |key, result|
24
225
  result[key] = Hashify[self[key]]
25
226
  end
26
227
  end
27
228
  alias_method :to_h, :to_hash
229
+
230
+ def new(changeset)
231
+ self.class[to_hash.merge(changeset)]
232
+ end
28
233
  end
29
234
  end
30
235
 
@@ -1,48 +1,78 @@
1
+ require 'dry/core/class_attributes'
2
+ require 'dry/equalizer'
3
+
1
4
  require 'dry/struct/errors'
2
5
 
3
6
  module Dry
4
7
  class Struct
8
+ # Class-level interface of {Struct} and {Value}
5
9
  module ClassInterface
6
- include Dry::Types::Builder
7
-
8
- attr_accessor :constructor
10
+ include Core::ClassAttributes
9
11
 
10
- attr_accessor :equalizer
11
-
12
- attr_writer :constructor_type
13
-
14
- protected :constructor=, :equalizer=, :constructor_type=
12
+ include Dry::Types::Builder
15
13
 
14
+ # @param [Module] base
16
15
  def self.extended(base)
17
- base.instance_variable_set(:@schema, {})
16
+ base.instance_variable_set(:@schema, EMPTY_HASH)
18
17
  end
19
18
 
19
+ # @param [Class] klass
20
20
  def inherited(klass)
21
21
  super
22
22
 
23
- klass.instance_variable_set(:@schema, {})
24
- klass.equalizer = Equalizer.new(*schema.keys)
25
- klass.constructor_type = constructor_type
23
+ klass.instance_variable_set(:@schema, EMPTY_HASH)
24
+ klass.equalizer Equalizer.new(*schema.keys)
26
25
  klass.send(:include, klass.equalizer)
27
26
 
28
- unless klass == Value
29
- klass.constructor = Types['coercible.hash']
30
- end
31
-
32
- klass.attributes({}) unless equal?(Struct)
33
- end
34
-
27
+ klass.attributes(EMPTY_HASH) unless equal?(Struct)
28
+ end
29
+
30
+ # Adds an attribute for this {Struct} with given `name` and `type`
31
+ # and modifies {.schema} accordingly.
32
+ #
33
+ # @param [Symbol] name name of the defined attribute
34
+ # @param [Dry::Types::Definition] type
35
+ # @return [Dry::Struct]
36
+ # @raise [RepeatedAttributeError] when trying to define attribute with the
37
+ # same name as previously defined one
38
+ #
39
+ # @example
40
+ # class Language < Dry::Struct
41
+ # attribute :name, Types::String
42
+ # end
43
+ #
44
+ # Language.schema
45
+ # #=> {name: #<Dry::Types::Definition primitive=String options={}>}
46
+ #
47
+ # ruby = Language.new(name: 'Ruby')
48
+ # ruby.name #=> 'Ruby'
35
49
  def attribute(name, type)
36
50
  attributes(name => type)
37
51
  end
38
52
 
53
+ # @param [Hash{Symbol => Dry::Types::Definition}] new_schema
54
+ # @return [Dry::Struct]
55
+ # @raise [RepeatedAttributeError] when trying to define attribute with the
56
+ # same name as previously defined one
57
+ # @see #attribute
58
+ # @example
59
+ # class Book1 < Dry::Struct
60
+ # attributes(
61
+ # title: Types::String,
62
+ # author: Types::String
63
+ # )
64
+ # end
65
+ #
66
+ # Book.schema
67
+ # #=> {title: #<Dry::Types::Definition primitive=String options={}>,
68
+ # # author: #<Dry::Types::Definition primitive=String options={}>}
39
69
  def attributes(new_schema)
40
70
  check_schema_duplication(new_schema)
41
71
 
42
72
  prev_schema = schema
43
73
 
44
74
  @schema = prev_schema.merge(new_schema)
45
- @constructor = Types['coercible.hash'].public_send(constructor_type, schema)
75
+ input Types['coercible.hash'].public_send(constructor_type, schema)
46
76
 
47
77
  attr_reader(*new_schema.keys)
48
78
  equalizer.instance_variable_get('@keys').concat(new_schema.keys)
@@ -50,6 +80,9 @@ module Dry
50
80
  self
51
81
  end
52
82
 
83
+ # @param [Hash{Symbol => Dry::Types::Definition, Dry::Struct}] new_schema
84
+ # @raise [RepeatedAttributeError] when trying to define attribute with the
85
+ # same name as previously defined one
53
86
  def check_schema_duplication(new_schema)
54
87
  shared_keys = new_schema.keys & (schema.keys - superclass.schema.keys)
55
88
 
@@ -57,37 +90,60 @@ module Dry
57
90
  end
58
91
  private :check_schema_duplication
59
92
 
60
- def constructor_type(type = nil)
61
- if type
62
- @constructor_type = type
63
- else
64
- @constructor_type || :strict
65
- end
66
- end
67
-
93
+ # @return [Hash{Symbol => Dry::Types::Definition, Dry::Struct}]
68
94
  def schema
69
- super_schema = superclass.respond_to?(:schema) ? superclass.schema : {}
95
+ super_schema = superclass.respond_to?(:schema) ? superclass.schema : EMPTY_HASH
70
96
  super_schema.merge(@schema)
71
97
  end
72
98
 
99
+ # @param [Hash{Symbol => Object},Dry::Struct] attributes
100
+ # @raise [Struct::Error] if the given attributes don't conform {#schema}
101
+ # with given {#constructor_type}
73
102
  def new(attributes = default_attributes)
74
103
  if attributes.instance_of?(self)
75
104
  attributes
76
105
  else
77
- super(constructor[attributes])
106
+ super(input[attributes])
78
107
  end
79
108
  rescue Types::SchemaError, Types::MissingKeyError, Types::UnknownKeysError => error
80
109
  raise Struct::Error, "[#{self}.new] #{error}"
81
110
  end
82
- alias_method :call, :new
83
- alias_method :[], :new
84
111
 
112
+ # Calls type constructor. The behavior is identical to `.new` but returns
113
+ # returns the input back if it's a subclass of the struct.
114
+ #
115
+ # @param [Hash{Symbol => Object},Dry::Struct] attributes
116
+ # @return [Dry::Struct]
117
+ def call(attributes = default_attributes)
118
+ return attributes if attributes.is_a?(self)
119
+ new(attributes)
120
+ end
121
+ alias_method :[], :call
122
+
123
+ # Retrieves default attributes from defined {.schema}.
124
+ # Used in a {Struct} constructor if no attributes provided to {.new}
125
+ #
126
+ # @return [Hash{Symbol => Object}]
85
127
  def default_attributes
128
+ check_invalid_schema_keys
86
129
  schema.each_with_object({}) { |(name, type), result|
87
- result[name] = type.default? ? type.evaluate : type[nil]
130
+ result[name] = type.evaluate if type.default?
88
131
  }
89
132
  end
90
133
 
134
+ def check_invalid_schema_keys
135
+ invalid_keys = schema.select { |name, type| type.instance_of?(String) }
136
+ raise ArgumentError, argument_error_msg(invalid_keys.keys) if invalid_keys.any?
137
+ end
138
+
139
+ def argument_error_msg(keys)
140
+ "Invaild argument for #{keys.join(', ')}"
141
+ end
142
+
143
+ # @param [Hash{Symbol => Object}] input
144
+ # @yieldparam [Dry::Types::Result::Failure] failure
145
+ # @yieldreturn [Dry::Types::ResultResult]
146
+ # @return [Dry::Types::Result]
91
147
  def try(input)
92
148
  Types::Result::Success.new(self[input])
93
149
  rescue Struct::Error => e
@@ -95,33 +151,49 @@ module Dry
95
151
  block_given? ? yield(failure) : failure
96
152
  end
97
153
 
154
+ # @param [({Symbol => Object})] args
155
+ # @return [Dry::Types::Result::Success]
98
156
  def success(*args)
99
157
  result(Types::Result::Success, *args)
100
158
  end
101
159
 
160
+ # @param [({Symbol => Object})] args
161
+ # @return [Dry::Types::Result::Failure]
102
162
  def failure(*args)
103
163
  result(Types::Result::Failure, *args)
104
164
  end
105
165
 
166
+ # @param [Class] klass
167
+ # @param [({Symbol => Object})] args
106
168
  def result(klass, *args)
107
169
  klass.new(*args)
108
170
  end
109
171
 
172
+ # @return [false]
110
173
  def default?
111
174
  false
112
175
  end
113
176
 
177
+ # @param [Object, Dry::Struct] value
178
+ # @return [Boolean]
114
179
  def valid?(value)
115
180
  self === value
116
181
  end
117
182
 
183
+ # @return [true]
118
184
  def constrained?
119
185
  true
120
186
  end
121
187
 
188
+ # @return [self]
122
189
  def primitive
123
190
  self
124
191
  end
192
+
193
+ # @return [false]
194
+ def optional?
195
+ false
196
+ end
125
197
  end
126
198
  end
127
199
  end
@@ -4,9 +4,13 @@ module Dry
4
4
 
5
5
  setting :namespace, self
6
6
 
7
+ # Raised when given input doesn't conform schema and constructor type
7
8
  Error = Class.new(TypeError)
8
9
 
10
+ # Raised when defining duplicate attributes
9
11
  class RepeatedAttributeError < ArgumentError
12
+ # @param [Symbol] key
13
+ # attribute name that is the same as previously defined one
10
14
  def initialize(key)
11
15
  super("Attribute :#{key} has already been defined")
12
16
  end
@@ -1,8 +1,10 @@
1
- # Converts value to hash recursively
2
-
3
1
  module Dry
4
2
  class Struct
3
+ # Helper for {Struct#to_hash} implementation
5
4
  module Hashify
5
+ # Converts value to hash recursively
6
+ # @param [#to_hash, #map, Object] value
7
+ # @return [Hash, Array]
6
8
  def self.[](value)
7
9
  if value.respond_to?(:to_hash)
8
10
  value.to_hash
@@ -2,7 +2,27 @@ require 'ice_nine'
2
2
 
3
3
  module Dry
4
4
  class Struct
5
+ # {Value} objects behave like {Struct}s but *deeply frozen*
6
+ # using [`ice_nine`](https://github.com/dkubb/ice_nine)
7
+ #
8
+ # @example
9
+ # class Location < Dry::Struct::Value
10
+ # attribute :lat, Types::Strict::Float
11
+ # attribute :lng, Types::Strict::Float
12
+ # end
13
+ #
14
+ # loc1 = Location.new(lat: 1.23, lng: 4.56)
15
+ # loc2 = Location.new(lat: 1.23, lng: 4.56)
16
+ #
17
+ # loc1.frozen? #=> true
18
+ # loc2.frozen? #=> true
19
+ # loc1 == loc2 #=> true
20
+ #
21
+ # @see https://github.com/dkubb/ice_nine
5
22
  class Value < self
23
+ # @param (see ClassInterface#new)
24
+ # @return [Value]
25
+ # @see https://github.com/dkubb/ice_nine
6
26
  def self.new(*)
7
27
  IceNine.deep_freeze(super)
8
28
  end
@@ -1,5 +1,5 @@
1
1
  module Dry
2
2
  class Struct
3
- VERSION = '0.2.1'.freeze
3
+ VERSION = '0.3.0'.freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dry-struct
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Solnica
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-02-27 00:00:00.000000000 Z
11
+ date: 2017-05-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-equalizer
@@ -58,6 +58,20 @@ dependencies:
58
58
  - - ">="
59
59
  - !ruby/object:Gem::Version
60
60
  version: 0.9.0
61
+ - !ruby/object:Gem::Dependency
62
+ name: dry-core
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '0.3'
68
+ type: :runtime
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '0.3'
61
75
  - !ruby/object:Gem::Dependency
62
76
  name: ice_nine
63
77
  requirement: !ruby/object:Gem::Requirement
@@ -114,6 +128,20 @@ dependencies:
114
128
  - - "~>"
115
129
  - !ruby/object:Gem::Version
116
130
  version: '3.3'
131
+ - !ruby/object:Gem::Dependency
132
+ name: yard
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - "~>"
136
+ - !ruby/object:Gem::Version
137
+ version: 0.9.5
138
+ type: :development
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - "~>"
143
+ - !ruby/object:Gem::Version
144
+ version: 0.9.5
117
145
  description: Typed structs and value objects.
118
146
  email:
119
147
  - piotr.solnica@gmail.com
@@ -124,6 +152,7 @@ files:
124
152
  - ".gitignore"
125
153
  - ".rspec"
126
154
  - ".travis.yml"
155
+ - ".yardopts"
127
156
  - CHANGELOG.md
128
157
  - Gemfile
129
158
  - LICENSE
@@ -162,7 +191,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
162
191
  version: '0'
163
192
  requirements: []
164
193
  rubyforge_project:
165
- rubygems_version: 2.6.10
194
+ rubygems_version: 2.6.11
166
195
  signing_key:
167
196
  specification_version: 4
168
197
  summary: Typed structs and value objects.