value_semantics 2.1.0 → 3.2.1

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
  SHA256:
3
- metadata.gz: 17ee24bc8ffd744493e9957a4cb7ee0071f0c33aa8560b3ed36689575b9c0ab1
4
- data.tar.gz: 05da8d260966f9257578f0ebf3891ba447b51032709bb75b39bdacba3e081961
3
+ metadata.gz: f122fa566277c213c7eb2a31b38af94d4287b1688d91da91bd5eea8044a041ba
4
+ data.tar.gz: 371bc15f0cc7449042b19d5064e4a28f76ec1d6c0aae2c64622adf3252621045
5
5
  SHA512:
6
- metadata.gz: 4a4da5150969146f5fd8cb06a17f8e43b1c897cd40f228cdddd7b2a8367fdbbceeacc66843668bf74a48575d72f752d3f24fd101c2ac7e946335688a1eec95a3
7
- data.tar.gz: c0e71a37be6df7bcafa4833f7b7cea4304468818a4391e020770c6f85e16edaf68a56c84c572f3bd26399aa85b2dc149abb48660d82750a656d746d87da5a16a
6
+ metadata.gz: a7ebe03be2de318e43027cc4d27ed737111654a5d74c0646f62691076e0f51938eb55966a3f04105f4a4c86d242a0134ca3f5fafa27089aedd4c51f2fb45abd9
7
+ data.tar.gz: ac4e7a9f938e0bd9193d4260a8c211db6a05554463b6312a6409499a8d22c7a34b281093cf2c487676fefd58915b21027a47c99a75619fb2b80c457672ced57e
@@ -1,13 +1,25 @@
1
1
  language: ruby
2
+ script: bin/test
3
+
4
+ # test old Ruby versions WITHOUT mutation testing
2
5
  rvm:
3
- - 2.3.7
4
- - 2.4.4
5
- - 2.5.1
6
- script: bin/mutation_test.sh
6
+ - 2.3.8
7
+ - 2.4.10
8
+ - 2.5.8
9
+ - 2.6.6
10
+ env: MUTATION_TEST=false
11
+
12
+ # test the latest Ruby version WITH mutation testing
13
+ matrix:
14
+ include:
15
+ - rvm: 2.7.1
16
+ env: MUTATION_TEST=true
17
+
18
+ # deploy gem on tagged commits, on the latest Ruby version only
7
19
  deploy:
8
20
  provider: rubygems
9
21
  on:
10
22
  tags: true
11
- rvm: 2.5.1
23
+ env: MUTATION_TEST=true
12
24
  api_key:
13
25
  secure: nL74QuUczEpA0qbhSBN2zjGdviWgKB3wR6vFvwervv1MZNWmwOQUYe99Oq9kPeyc8/x2MR/H6PQm5qbrk/WAfRede01WxlZ/EBUW+9CYGrxcBsGONx9IULO8A0I8/yN/YJHW2vjo3dfR66EwVsXTVWq8U63PRRcwJIyTqnIiUm2sxauMQoPRBbXG+pD9v/EJSn3ugpdtxp0lVYDn8LDKk5Ho4/wbpY4ML11XUJa9mz9CyR/GsAzdy5FTXaDMOwuWOVEx9cab7m4qPOBhmlJY4TrmooFpxTxRwChcvByjq1IboEd2M3RT5on7Q/xDTlHSOuT0OS8mnS2AocGT4a1gC+W/xOlghgEcN+xs2V5mfucR6+iUYlCy32uz1w3ey7T2X5xN4ubut09r1xLi7eu1NisAoAc+GOJ4TIxQNqkeRhY4X/fs8j7SMfOEMDr6pPxSLKZxgSvExt+IbdcZD/uQ7rTBQkadYCbc9MX5dHazBievmar3ZsFffbIf+n13FVDXsaPgRt7DlFM5dqGrEwVwt1jFRhdFuDCjkj4QWOLn7E1uY3XqgrqGvgUBlF8Znwc6qicW8zxV4SIWhqIzCOH6L9WIZGLHNq0remoCd9sq9Ter9av3jL+6UmZRRAr+JceeZfZmsYIXKomECzleM9FXMx7FXlpjJKOlf3JnrfeCTwI=
@@ -0,0 +1,24 @@
1
+ # Changelog
2
+
3
+ Notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+
9
+ ## [3.2.1] - 2020-07-11
10
+ ### Fixed
11
+ - Fix warnings new to Ruby 2.7 about keyword arguments
12
+
13
+ ## [3.2.0] - 2019-09-30
14
+ ### Added
15
+ - `ValueSemantics::Struct`, a convenience for creating a new class and mixing
16
+ in ValueSemantics in a single step.
17
+
18
+ ## [3.1.0] - 2019-06-30
19
+ ### Added
20
+ - Built-in PP support for value classes
21
+
22
+ ## [3.0.0] - 2019-01-27
23
+
24
+ First public release
data/Gemfile CHANGED
@@ -1,6 +1,8 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
3
+ source 'https://oss:fLUos7k6c7Ak7zjhwbYphPJbwBk1Uuew@gem.mutant.dev' do
4
+ gem 'mutant-license'
5
+ end
4
6
 
5
7
  # Specify your gem's dependencies in the gemspec
6
8
  gemspec
data/README.md CHANGED
@@ -5,15 +5,20 @@
5
5
  ValueSemantics
6
6
  ==============
7
7
 
8
- Create value classes quickly, with all the [conventions of a good value object](https://github.com/zverok/good-value-object).
8
+ A gem for making value classes.
9
9
 
10
- Generates modules that provide value semantics for a given set of attributes.
11
- Provides the behaviour of an immutable struct-like value class,
12
- with light-weight validation and coercion.
10
+ Generates modules that provide [conventional value semantics](https://github.com/zverok/good-value-object) for a given set of attributes.
11
+ The behaviour is similar to an immutable `Struct` class,
12
+ plus extensible, lightweight validation and coercion.
13
13
 
14
14
  These are intended for internal use, as opposed to validating user input like ActiveRecord.
15
- Invalid or missing attributes cause an exception intended for developers,
16
- not an error message intended for the user.
15
+ Invalid or missing attributes cause an exception for developers,
16
+ not an error message intended for application users.
17
+
18
+ See the [announcement blog post][] for some of the rationale behind the gem, and some [discussion on Reddit].
19
+
20
+ [announcement blog post]: https://www.rubypigeon.com/posts/value-semantics-gem-for-making-value-classes/
21
+ [discussion on Reddit]: https://www.reddit.com/r/ruby/comments/akz4fs/valuesemanticsa_gem_for_making_value_classes/
17
22
 
18
23
 
19
24
  Defining and Creating Value Objects
@@ -103,7 +108,7 @@ Defaults
103
108
  --------
104
109
 
105
110
  Defaults can be specified in one of two ways:
106
- the `:default` option, or the `default_generator` option.
111
+ the `:default` option, or the `:default_generator` option.
107
112
 
108
113
  ```ruby
109
114
  class Cat
@@ -164,8 +169,8 @@ for common situations:
164
169
  class LightSwitch
165
170
  include ValueSemantics.for_attributes {
166
171
 
167
- # Boolean: only allows `true` or `false`
168
- on? Boolean()
172
+ # Bool: only allows `true` or `false`
173
+ on? Bool()
169
174
 
170
175
  # ArrayOf: validates elements in an array
171
176
  light_ids ArrayOf(Integer)
@@ -174,7 +179,7 @@ class LightSwitch
174
179
  color Either(Integer, String, nil)
175
180
 
176
181
  # these validators are composable
177
- wierd_attr Either(Boolean(), ArrayOf(Boolean()))
182
+ wierd_attr Either(Bool(), ArrayOf(Bool()))
178
183
  }
179
184
  end
180
185
 
@@ -299,6 +304,21 @@ For example, the default value could be a string,
299
304
  which would then be coerced into an `IPAddr` object.
300
305
 
301
306
 
307
+ ## ValueSemantics::Struct
308
+
309
+ This is a convenience for making a new class and including ValueSemantics in
310
+ one step, similar to how `Struct` works from the Ruby standard library. For
311
+ example:
312
+
313
+ ```ruby
314
+ Cat = ValueSemantics::Struct.new do
315
+ name String, default: "Mittens"
316
+ end
317
+
318
+ Cat.new.name #=> "Mittens"
319
+ ```
320
+
321
+
302
322
  ## Installation
303
323
 
304
324
  Add this line to your application's Gemfile:
@@ -321,6 +341,7 @@ Or install it yourself as:
321
341
  Bug reports and pull requests are welcome on GitHub at:
322
342
  https://github.com/tomdalling/value_semantics
323
343
 
344
+ Keep in mind that this gem aims to be as close to 100% backwards compatible as possible.
324
345
 
325
346
  ## License
326
347
 
@@ -0,0 +1,15 @@
1
+ #!/bin/bash
2
+ set -ue
3
+
4
+ MUTANT_PATTERN=${1:-ValueSemantics*}
5
+
6
+ # if $MUTATION_TEST is false, just run RSpec
7
+ if [[ "${MUTATION_TEST:-true}" == "false" ]] ; then
8
+ bundle exec rspec
9
+ else
10
+ bundle exec mutant \
11
+ --include lib \
12
+ --require value_semantics \
13
+ --use rspec "$MUTANT_PATTERN" \
14
+ --ignore-subject "ValueSemantics::Struct.new" # causes unfixable failure I don't want to deal with
15
+ fi
@@ -1,39 +1,80 @@
1
1
  module ValueSemantics
2
+ class Error < StandardError; end
3
+ class UnrecognizedAttributes < Error; end
4
+ class NoDefaultValue < Error; end
5
+ class MissingAttributes < Error; end
6
+
2
7
  NOT_SPECIFIED = Object.new.freeze
3
8
 
9
+ #
10
+ # Creates a module via the DSL
11
+ #
12
+ # @yield The block containing the DSL
13
+ # @return [Module]
14
+ #
15
+ # @see DSL
16
+ # @see InstanceMethods
17
+ #
4
18
  def self.for_attributes(&block)
5
- attributes = DSL.run(&block)
6
- generate_module(attributes.freeze)
19
+ recipe = DSL.run(&block)
20
+ bake_module(recipe)
7
21
  end
8
22
 
9
- def self.generate_module(attributes)
23
+ #
24
+ # Creates a module from a {Recipe}
25
+ #
26
+ # @param recipe [Recipe]
27
+ # @return [Module]
28
+ #
29
+ def self.bake_module(recipe)
10
30
  Module.new do
11
- # include all the instance methods
12
- include(Semantics)
31
+ const_set(:VALUE_SEMANTICS_RECIPE__, recipe)
32
+ include(InstanceMethods)
13
33
 
14
34
  # define the attr readers
15
- attributes.each do |attr|
35
+ recipe.attributes.each do |attr|
16
36
  module_eval("def #{attr.name}; #{attr.instance_variable}; end")
17
37
  end
18
38
 
19
- # define BaseClass.attributes class method
20
- const_set(:ATTRIBUTES__, attributes)
21
39
  def self.included(base)
22
- base.const_set(:ValueSemantics_Generated, self)
23
- class << base
24
- def attributes
25
- self::ATTRIBUTES__
26
- end
27
- end
40
+ base.const_set(:ValueSemantics_Attributes, self)
41
+ base.extend(ClassMethods)
28
42
  end
29
43
  end
30
44
  end
31
45
 
32
- module Semantics
46
+ #
47
+ # All the class methods available on ValueSemantics classes
48
+ #
49
+ # When a ValueSemantics module is included into a class,
50
+ # the class is extended by this module.
51
+ #
52
+ module ClassMethods
53
+ #
54
+ # @return [Recipe] the recipe used to build the ValueSemantics module that
55
+ # was included into this class.
56
+ #
57
+ def value_semantics
58
+ self::VALUE_SEMANTICS_RECIPE__
59
+ end
60
+ end
61
+
62
+ #
63
+ # All the instance methods available on ValueSemantics objects
64
+ #
65
+ module InstanceMethods
66
+ #
67
+ # Creates a value object based on a Hash of attributes
68
+ #
69
+ # @param given_attrs [Hash] a hash of attributes, with symbols for keys
70
+ # @raise [UnrecognizedAttributes] if given_attrs contains keys that are not attributes
71
+ # @raise [MissingAttributes] if given_attrs is missing any attributes that do not have defaults
72
+ # @raise [ArgumentError] if any attribute values do no pass their validators
73
+ #
33
74
  def initialize(given_attrs = {})
34
75
  remaining_attrs = given_attrs.dup
35
76
 
36
- self.class.attributes.each do |attr|
77
+ self.class.value_semantics.attributes.each do |attr|
37
78
  key, value = attr.determine_from!(remaining_attrs, self.class)
38
79
  instance_variable_set(attr.instance_variable, value)
39
80
  remaining_attrs.delete(key)
@@ -41,30 +82,54 @@ module ValueSemantics
41
82
 
42
83
  unless remaining_attrs.empty?
43
84
  unrecognised = remaining_attrs.keys.map(&:inspect).join(', ')
44
- raise ArgumentError, "Unrecognised attributes: #{unrecognised}"
85
+ raise UnrecognizedAttributes, "Unrecognized attributes: #{unrecognised}"
45
86
  end
46
87
  end
47
88
 
89
+ #
90
+ # Creates a copy of this object, with the given attributes changed (non-destructive update)
91
+ #
92
+ # @param new_attrs [Hash] the attributes to change
93
+ # @return A new object, with the attribute changes applied
94
+ #
48
95
  def with(new_attrs)
49
96
  self.class.new(to_h.merge(new_attrs))
50
97
  end
51
98
 
99
+ #
100
+ # @return [Hash] all of the attributes
101
+ #
52
102
  def to_h
53
- self.class.attributes
103
+ self.class.value_semantics.attributes
54
104
  .map { |attr| [attr.name, public_send(attr.name)] }
55
105
  .to_h
56
106
  end
57
107
 
108
+ #
109
+ # Loose equality
110
+ #
111
+ # @return [Boolean] whether all attributes are equal, and the object
112
+ # classes are ancestors of eachother in any way
113
+ #
58
114
  def ==(other)
59
115
  (other.is_a?(self.class) || is_a?(other.class)) && other.to_h.eql?(to_h)
60
116
  end
61
117
 
118
+ #
119
+ # Strict equality
120
+ #
121
+ # @return [Boolean] whether all attribuets are equal, and both objects
122
+ # has the exact same class
123
+ #
62
124
  def eql?(other)
63
125
  other.class.equal?(self.class) && other.to_h.eql?(to_h)
64
126
  end
65
127
 
128
+ #
129
+ # Unique-ish integer, based on attributes and class of the object
130
+ #
66
131
  def hash
67
- @__hash ||= (to_h.hash ^ self.class.hash)
132
+ to_h.hash ^ self.class.hash
68
133
  end
69
134
 
70
135
  def inspect
@@ -74,14 +139,32 @@ module ValueSemantics
74
139
 
75
140
  "#<#{self.class} #{attrs}>"
76
141
  end
142
+
143
+ def pretty_print(pp)
144
+ pp.object_group(self) do
145
+ to_h.each do |attr, value|
146
+ pp.breakable
147
+ pp.text("#{attr}=")
148
+ pp.pp(value)
149
+ end
150
+ end
151
+ end
77
152
  end
78
153
 
154
+ #
155
+ # Represents a single attribute of a value class
156
+ #
79
157
  class Attribute
80
- NO_DEFAULT_GENERATOR = ->{ raise "Attribute does not have a default value" }
158
+ NO_DEFAULT_GENERATOR = lambda do
159
+ raise NoDefaultValue, "Attribute does not have a default value"
160
+ end
81
161
 
82
162
  attr_reader :name, :validator, :coercer, :default_generator
83
163
 
84
- def initialize(name:, default_generator:, validator:, coercer:)
164
+ def initialize(name:,
165
+ default_generator: NO_DEFAULT_GENERATOR,
166
+ validator: Anything,
167
+ coercer: nil)
85
168
  @name = name.to_sym
86
169
  @default_generator = default_generator
87
170
  @validator = validator
@@ -89,10 +172,35 @@ module ValueSemantics
89
172
  freeze
90
173
  end
91
174
 
175
+ def self.define(name,
176
+ validator=Anything,
177
+ default: NOT_SPECIFIED,
178
+ default_generator: nil,
179
+ coerce: nil)
180
+ generator = begin
181
+ if default_generator && !default.equal?(NOT_SPECIFIED)
182
+ raise ArgumentError, "Attribute '#{name}' can not have both a :default and a :default_generator"
183
+ elsif default_generator
184
+ default_generator
185
+ elsif !default.equal?(NOT_SPECIFIED)
186
+ ->{ default }
187
+ else
188
+ NO_DEFAULT_GENERATOR
189
+ end
190
+ end
191
+
192
+ new(
193
+ name: name,
194
+ validator: validator,
195
+ default_generator: generator,
196
+ coercer: coerce,
197
+ )
198
+ end
199
+
92
200
  def determine_from!(attr_hash, klass)
93
201
  raw_value = attr_hash.fetch(name) do
94
202
  if default_generator.equal?(NO_DEFAULT_GENERATOR)
95
- raise ArgumentError, "Value missing for attribute '#{name}'"
203
+ raise MissingAttributes, "Value missing for attribute '#{name}'"
96
204
  else
97
205
  default_generator.call
98
206
  end
@@ -130,11 +238,38 @@ module ValueSemantics
130
238
  end
131
239
  end
132
240
 
241
+ #
242
+ # Contains all the configuration necessary to bake a ValueSemantics module
243
+ #
244
+ # @see ValueSemantics.bake_module
245
+ #
246
+ class Recipe
247
+ attr_reader :attributes
248
+
249
+ def initialize(attributes:)
250
+ @attributes = attributes
251
+ freeze
252
+ end
253
+ end
254
+
255
+ #
256
+ # Builds a {Recipe} via DSL methods
257
+ #
258
+ # DSL blocks are <code>instance_eval</code>d against an object of this class.
259
+ #
260
+ # @see Recipe
261
+ # @see ValueSemantics.for_attributes
262
+ #
133
263
  class DSL
264
+ #
265
+ # Builds a {Recipe} from a DSL block
266
+ #
267
+ # @yield to the block containing the DSL
268
+ # @return [Recipe]
134
269
  def self.run(&block)
135
270
  dsl = new
136
271
  dsl.instance_eval(&block)
137
- dsl.__attributes
272
+ Recipe.new(attributes: dsl.__attributes.freeze)
138
273
  end
139
274
 
140
275
  attr_reader :__attributes
@@ -143,8 +278,8 @@ module ValueSemantics
143
278
  @__attributes = []
144
279
  end
145
280
 
146
- def Boolean
147
- Boolean
281
+ def Bool
282
+ Bool
148
283
  end
149
284
 
150
285
  def Either(*subvalidators)
@@ -159,60 +294,47 @@ module ValueSemantics
159
294
  ArrayOf.new(element_validator)
160
295
  end
161
296
 
162
- def def_attr(attr_name,
163
- validator=Anything,
164
- default: NOT_SPECIFIED,
165
- default_generator: nil,
166
- coerce: nil
167
- )
168
- generator = begin
169
- if default_generator && !default.equal?(NOT_SPECIFIED)
170
- raise ArgumentError, "Attribute '#{attr_name}' can not have both a default, and a default_generator"
171
- elsif default_generator
172
- default_generator
173
- elsif !default.equal?(NOT_SPECIFIED)
174
- ->{ default }
175
- else
176
- Attribute::NO_DEFAULT_GENERATOR
177
- end
178
- end
179
-
180
- __attributes << Attribute.new(
181
- name: attr_name,
182
- validator: validator,
183
- default_generator: generator,
184
- coercer: coerce
185
- )
297
+ def def_attr(*args, **kwargs)
298
+ __attributes << Attribute.define(*args, **kwargs)
186
299
  end
187
300
 
188
- def method_missing(name, *args)
301
+ def method_missing(name, *args, **kwargs)
189
302
  if respond_to_missing?(name)
190
- def_attr(name, *args)
303
+ def_attr(name, *args, **kwargs)
191
304
  else
192
305
  super
193
306
  end
194
307
  end
195
308
 
196
309
  def respond_to_missing?(method_name, _include_private=nil)
197
- first_letter = method_name[0]
310
+ first_letter = method_name.to_s.each_char.first
198
311
  first_letter.eql?(first_letter.downcase)
199
312
  end
200
313
  end
201
314
 
202
- module Boolean
203
- extend self
204
-
205
- def ===(value)
315
+ #
316
+ # Validator that only matches `true` and `false`
317
+ #
318
+ module Bool
319
+ # @return [Boolean]
320
+ def self.===(value)
206
321
  true.equal?(value) || false.equal?(value)
207
322
  end
208
323
  end
209
324
 
325
+ #
326
+ # Validator that matches any and all values
327
+ #
210
328
  module Anything
329
+ # @return [true]
211
330
  def self.===(_)
212
331
  true
213
332
  end
214
333
  end
215
334
 
335
+ #
336
+ # Validator that matches if any of the given subvalidators matches
337
+ #
216
338
  class Either
217
339
  attr_reader :subvalidators
218
340
 
@@ -221,11 +343,15 @@ module ValueSemantics
221
343
  freeze
222
344
  end
223
345
 
346
+ # @return [Boolean]
224
347
  def ===(value)
225
348
  subvalidators.any? { |sv| sv === value }
226
349
  end
227
350
  end
228
351
 
352
+ #
353
+ # Validator that matches arrays if each element matches a given subvalidator
354
+ #
229
355
  class ArrayOf
230
356
  attr_reader :element_validator
231
357
 
@@ -234,9 +360,28 @@ module ValueSemantics
234
360
  freeze
235
361
  end
236
362
 
363
+ # @return [Boolean]
237
364
  def ===(value)
238
365
  Array === value && value.all? { |element| element_validator === element }
239
366
  end
240
367
  end
241
368
 
369
+ #
370
+ # ValueSemantics equivalent of the Struct class from the Ruby standard
371
+ # library
372
+ #
373
+ class Struct
374
+ #
375
+ # Creates a new Class with ValueSemantics mixed in
376
+ #
377
+ # @yield a block containing ValueSemantics DSL
378
+ # @return [Class] the newly created class
379
+ #
380
+ def self.new(&block)
381
+ klass = Class.new
382
+ klass.include(ValueSemantics.for_attributes(&block))
383
+ klass
384
+ end
385
+ end
386
+
242
387
  end
@@ -1,3 +1,3 @@
1
1
  module ValueSemantics
2
- VERSION = "2.1.0"
2
+ VERSION = "3.2.1"
3
3
  end
@@ -9,13 +9,11 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["Tom Dalling"]
10
10
  spec.email = [["tom", "@", "tomdalling.com"].join]
11
11
 
12
- spec.summary = %q{Create value classes quickly, with all the proper conventions.}
12
+ spec.summary = %q{Makes value classes, with lightweight validation and coercion.}
13
13
  spec.description = %q{
14
- Create value classes quickly, with all the proper conventions.
15
-
16
- Generates modules that provide value semantics for a given set of attributes.
17
- Provides the behaviour of an immutable struct-like value class,
18
- with light-weight validation and coercion.
14
+ Generates modules that provide conventional value semantics for a given set of attributes.
15
+ The behaviour is similar to an immutable `Struct` class,
16
+ plus extensible, lightweight validation and coercion.
19
17
  }
20
18
  spec.homepage = "https://github.com/tomdalling/value_semantics"
21
19
  spec.license = "MIT"
@@ -27,9 +25,10 @@ Gem::Specification.new do |spec|
27
25
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
26
  spec.require_paths = ["lib"]
29
27
 
30
- spec.add_development_dependency "bundler", "~> 1.15"
31
- spec.add_development_dependency "rspec", "~> 3.7.0"
28
+ spec.add_development_dependency "bundler", ">= 1.15"
29
+ spec.add_development_dependency "rspec", "~> 3.7"
32
30
  spec.add_development_dependency "mutant-rspec"
31
+ spec.add_development_dependency "yard"
33
32
  spec.add_development_dependency "byebug"
34
33
  spec.add_development_dependency "gem-release"
35
34
  end
metadata CHANGED
@@ -1,27 +1,27 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: value_semantics
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 3.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tom Dalling
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-12-21 00:00:00.000000000 Z
11
+ date: 2020-07-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1.15'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.15'
27
27
  - !ruby/object:Gem::Dependency
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 3.7.0
33
+ version: '3.7'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 3.7.0
40
+ version: '3.7'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: mutant-rspec
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: yard
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: byebug
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -80,10 +94,9 @@ dependencies:
80
94
  - - ">="
81
95
  - !ruby/object:Gem::Version
82
96
  version: '0'
83
- description: "\n Create value classes quickly, with all the proper conventions.\n\n
84
- \ Generates modules that provide value semantics for a given set of attributes.\n
85
- \ Provides the behaviour of an immutable struct-like value class,\n with light-weight
86
- validation and coercion.\n "
97
+ description: "\n Generates modules that provide conventional value semantics for
98
+ a given set of attributes.\n The behaviour is similar to an immutable `Struct`
99
+ class,\n plus extensible, lightweight validation and coercion.\n "
87
100
  email:
88
101
  - tom@tomdalling.com
89
102
  executables: []
@@ -93,12 +106,13 @@ files:
93
106
  - ".gitignore"
94
107
  - ".rspec"
95
108
  - ".travis.yml"
109
+ - CHANGELOG.md
96
110
  - Gemfile
97
111
  - LICENSE.txt
98
112
  - README.md
99
113
  - bin/console
100
- - bin/mutation_test.sh
101
114
  - bin/setup
115
+ - bin/test
102
116
  - lib/value_semantics.rb
103
117
  - lib/value_semantics/version.rb
104
118
  - value_semantics.gemspec
@@ -121,8 +135,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
121
135
  - !ruby/object:Gem::Version
122
136
  version: '0'
123
137
  requirements: []
124
- rubygems_version: 3.0.0
138
+ rubyforge_project:
139
+ rubygems_version: 2.7.7
125
140
  signing_key:
126
141
  specification_version: 4
127
- summary: Create value classes quickly, with all the proper conventions.
142
+ summary: Makes value classes, with lightweight validation and coercion.
128
143
  test_files: []
@@ -1,6 +0,0 @@
1
- #!/bin/sh
2
- set -ue
3
-
4
- PATTERN=${1:-ValueSemantics*}
5
-
6
- bundle exec mutant --include lib --require value_semantics --use rspec "$PATTERN"