stannum 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +49 -0
- data/README.md +130 -1200
- data/config/locales/en.rb +4 -0
- data/lib/stannum/association.rb +293 -0
- data/lib/stannum/associations/many.rb +250 -0
- data/lib/stannum/associations/one.rb +106 -0
- data/lib/stannum/associations.rb +11 -0
- data/lib/stannum/attribute.rb +86 -8
- data/lib/stannum/constraints/base.rb +3 -5
- data/lib/stannum/constraints/enum.rb +1 -1
- data/lib/stannum/constraints/equality.rb +1 -1
- data/lib/stannum/constraints/format.rb +72 -0
- data/lib/stannum/constraints/hashes/extra_keys.rb +13 -13
- data/lib/stannum/constraints/hashes/indifferent_extra_keys.rb +47 -0
- data/lib/stannum/constraints/hashes.rb +6 -2
- data/lib/stannum/constraints/identity.rb +1 -1
- data/lib/stannum/constraints/properties/base.rb +124 -0
- data/lib/stannum/constraints/properties/do_not_match_property.rb +117 -0
- data/lib/stannum/constraints/properties/match_property.rb +117 -0
- data/lib/stannum/constraints/properties/matching.rb +112 -0
- data/lib/stannum/constraints/properties.rb +17 -0
- data/lib/stannum/constraints/signature.rb +2 -2
- data/lib/stannum/constraints/tuples/extra_items.rb +6 -6
- data/lib/stannum/constraints/type.rb +4 -4
- data/lib/stannum/constraints/types/array_type.rb +2 -2
- data/lib/stannum/constraints/types/hash_type.rb +4 -4
- data/lib/stannum/constraints/union.rb +1 -1
- data/lib/stannum/constraints/uuid.rb +30 -0
- data/lib/stannum/constraints.rb +3 -0
- data/lib/stannum/contract.rb +7 -7
- data/lib/stannum/contracts/array_contract.rb +2 -7
- data/lib/stannum/contracts/base.rb +15 -15
- data/lib/stannum/contracts/builder.rb +15 -4
- data/lib/stannum/contracts/hash_contract.rb +3 -9
- data/lib/stannum/contracts/indifferent_hash_contract.rb +15 -2
- data/lib/stannum/contracts/map_contract.rb +6 -10
- data/lib/stannum/contracts/parameters/arguments_contract.rb +1 -1
- data/lib/stannum/contracts/parameters/keywords_contract.rb +1 -1
- data/lib/stannum/contracts/parameters/signature_contract.rb +1 -1
- data/lib/stannum/contracts/parameters_contract.rb +4 -4
- data/lib/stannum/contracts/tuple_contract.rb +6 -6
- data/lib/stannum/entities/associations.rb +451 -0
- data/lib/stannum/entities/attributes.rb +316 -0
- data/lib/stannum/entities/constraints.rb +178 -0
- data/lib/stannum/entities/primary_key.rb +148 -0
- data/lib/stannum/entities/properties.rb +208 -0
- data/lib/stannum/entities.rb +16 -0
- data/lib/stannum/entity.rb +87 -0
- data/lib/stannum/errors.rb +12 -16
- data/lib/stannum/messages/default_strategy.rb +2 -2
- data/lib/stannum/parameter_validation.rb +10 -10
- data/lib/stannum/rspec/match_errors_matcher.rb +7 -7
- data/lib/stannum/rspec/validate_parameter.rb +2 -2
- data/lib/stannum/rspec/validate_parameter_matcher.rb +22 -20
- data/lib/stannum/schema.rb +117 -76
- data/lib/stannum/struct.rb +12 -346
- data/lib/stannum/support/optional.rb +1 -1
- data/lib/stannum/version.rb +4 -4
- data/lib/stannum.rb +6 -0
- metadata +26 -85
@@ -0,0 +1,208 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'stannum/entities'
|
4
|
+
|
5
|
+
module Stannum::Entities
|
6
|
+
# Abstract module for handling heterogenous entity properties.
|
7
|
+
#
|
8
|
+
# This module provides a base for accessing and mutating entity properties
|
9
|
+
# such as attributes and associations.
|
10
|
+
module Properties
|
11
|
+
MEMORY_ADDRESS_PATTERN = /0x([0-9a-f]+)/
|
12
|
+
private_constant :MEMORY_ADDRESS_PATTERN
|
13
|
+
|
14
|
+
# @param properties [Hash] the properties used to initialize the entity.
|
15
|
+
def initialize(**properties)
|
16
|
+
set_properties(properties, force: true)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Compares the entity with the other object.
|
20
|
+
#
|
21
|
+
# The other object must be an instance of the current class. In addition,
|
22
|
+
# the properties hashes of the two objects must be equal.
|
23
|
+
#
|
24
|
+
# @return true if the object is a matching entity.
|
25
|
+
def ==(other)
|
26
|
+
return false unless other.class == self.class
|
27
|
+
|
28
|
+
properties == other.properties
|
29
|
+
end
|
30
|
+
|
31
|
+
# Retrieves the property with the given key.
|
32
|
+
#
|
33
|
+
# @param property [String, Symbol] The property key.
|
34
|
+
#
|
35
|
+
# @return [Object] the value of the property.
|
36
|
+
#
|
37
|
+
# @raise ArgumentError if the key is not a valid property.
|
38
|
+
def [](property)
|
39
|
+
tools.assertions.validate_name(property, as: 'property')
|
40
|
+
|
41
|
+
get_property(property)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Sets the given property to the given value.
|
45
|
+
#
|
46
|
+
# @param property [String, Symbol] The property key.
|
47
|
+
# @param value [Object] The value for the property.
|
48
|
+
#
|
49
|
+
# @raise ArgumentError if the key is not a valid property.
|
50
|
+
def []=(property, value)
|
51
|
+
tools.assertions.validate_name(property, as: 'property')
|
52
|
+
|
53
|
+
set_property(property, value)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Updates the struct's properties with the given values.
|
57
|
+
#
|
58
|
+
# This method is used to update some (but not all) of the properties of the
|
59
|
+
# struct. For each key in the hash, it calls the corresponding writer method
|
60
|
+
# with the value for that property. If the value is nil, this will set the
|
61
|
+
# property value to the default for that property.
|
62
|
+
#
|
63
|
+
# Any properties that are not in the given hash are unchanged.
|
64
|
+
#
|
65
|
+
# If the properties hash includes any keys that do not correspond to an
|
66
|
+
# property, the struct will raise an error.
|
67
|
+
#
|
68
|
+
# @param properties [Hash] The initial properties for the struct.
|
69
|
+
#
|
70
|
+
# @raise ArgumentError if the key is not a valid property.
|
71
|
+
#
|
72
|
+
# @see #properties=
|
73
|
+
def assign_properties(properties)
|
74
|
+
unless properties.is_a?(Hash)
|
75
|
+
raise ArgumentError, 'properties must be a Hash'
|
76
|
+
end
|
77
|
+
|
78
|
+
set_properties(properties, force: false)
|
79
|
+
end
|
80
|
+
alias assign assign_properties
|
81
|
+
|
82
|
+
# @return [String] a string representation of the entity and its properties.
|
83
|
+
def inspect
|
84
|
+
inspect_with_options
|
85
|
+
end
|
86
|
+
|
87
|
+
# @param options [Hash] options for inspecting the entity.
|
88
|
+
#
|
89
|
+
# @option options memory_address [Boolean] if true, displays the memory
|
90
|
+
# address of the object (as per Object#inspect). Defaults to false.
|
91
|
+
# @option options properties [Boolean] if true, displays the entity
|
92
|
+
# properties. Defaults to true.
|
93
|
+
#
|
94
|
+
# @return [String] a string representation of the entity and its properties.
|
95
|
+
def inspect_with_options(**options)
|
96
|
+
address = options[:memory_address] ? ":#{memory_address}" : ''
|
97
|
+
mapped = inspect_properties(**options)
|
98
|
+
|
99
|
+
"#<#{self.class.name}#{address}#{mapped}>"
|
100
|
+
end
|
101
|
+
|
102
|
+
# Collects the entity properties.
|
103
|
+
#
|
104
|
+
# @return [Hash<String, Object>] the entity properties.
|
105
|
+
def properties
|
106
|
+
{}
|
107
|
+
end
|
108
|
+
|
109
|
+
# Replaces the entity's properties with the given values.
|
110
|
+
#
|
111
|
+
# This method is used to update all of the properties of the entity. For
|
112
|
+
# each property, the writer method is called with the value from the hash,
|
113
|
+
# or nil if the corresponding key is not present in the hash. Any nil or
|
114
|
+
# missing values set the property value to that property's default value, if
|
115
|
+
# any.
|
116
|
+
#
|
117
|
+
# If the properties hash includes any keys that do not correspond to a valid
|
118
|
+
# property, the entity will raise an error.
|
119
|
+
#
|
120
|
+
# @param properties [Hash] the properties to assign to the entity.
|
121
|
+
#
|
122
|
+
# @raise ArgumentError if any key is not a valid property.
|
123
|
+
#
|
124
|
+
# @see #assign_properties
|
125
|
+
def properties=(properties)
|
126
|
+
unless properties.is_a?(Hash)
|
127
|
+
raise ArgumentError, 'properties must be a Hash'
|
128
|
+
end
|
129
|
+
|
130
|
+
set_properties(properties, force: true)
|
131
|
+
end
|
132
|
+
|
133
|
+
# Returns a Hash representation of the entity.
|
134
|
+
#
|
135
|
+
# @return [Hash<String, Object>] the entity properties.
|
136
|
+
#
|
137
|
+
# @see #properties
|
138
|
+
def to_h
|
139
|
+
properties
|
140
|
+
end
|
141
|
+
|
142
|
+
private
|
143
|
+
|
144
|
+
def bisect_properties(properties, expected)
|
145
|
+
matching = {}
|
146
|
+
non_matching = {}
|
147
|
+
|
148
|
+
properties.each do |key, value|
|
149
|
+
if valid_property_key?(key) && expected.key?(key.to_s)
|
150
|
+
matching[key.to_s] = value
|
151
|
+
else
|
152
|
+
non_matching[key] = value
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
[matching, non_matching]
|
157
|
+
end
|
158
|
+
|
159
|
+
def get_property(key)
|
160
|
+
raise ArgumentError, "unknown property #{key.inspect}"
|
161
|
+
end
|
162
|
+
|
163
|
+
def handle_invalid_properties(properties, as: 'property')
|
164
|
+
properties.each_key do |key|
|
165
|
+
tools.assertions.assert_name(key, as:, error_class: ArgumentError)
|
166
|
+
end
|
167
|
+
|
168
|
+
raise ArgumentError, invalid_properties_message(properties, as:)
|
169
|
+
end
|
170
|
+
|
171
|
+
def inspect_properties(**)
|
172
|
+
''
|
173
|
+
end
|
174
|
+
|
175
|
+
def invalid_properties_message(properties, as: 'property')
|
176
|
+
"unknown #{tools.int.pluralize(properties.size, as)} " +
|
177
|
+
properties.keys.map(&:inspect).join(', ')
|
178
|
+
end
|
179
|
+
|
180
|
+
def memory_address
|
181
|
+
Object
|
182
|
+
.instance_method(:inspect)
|
183
|
+
.bind(self)
|
184
|
+
.call
|
185
|
+
.match(MEMORY_ADDRESS_PATTERN)[1]
|
186
|
+
end
|
187
|
+
|
188
|
+
def set_property(key, _)
|
189
|
+
raise ArgumentError, "unknown property #{key.inspect}"
|
190
|
+
end
|
191
|
+
|
192
|
+
def set_properties(properties, **_)
|
193
|
+
return if properties.empty?
|
194
|
+
|
195
|
+
handle_invalid_properties(properties)
|
196
|
+
end
|
197
|
+
|
198
|
+
def tools
|
199
|
+
SleepingKingStudios::Tools::Toolbelt.instance
|
200
|
+
end
|
201
|
+
|
202
|
+
def valid_property_key?(key)
|
203
|
+
return false unless key.is_a?(String) || key.is_a?(Symbol)
|
204
|
+
|
205
|
+
!key.empty?
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'sleeping_king_studios/tools/toolbox/mixin'
|
4
|
+
|
5
|
+
require 'stannum/entities'
|
6
|
+
|
7
|
+
module Stannum
|
8
|
+
# Namespace for modules implementing Entity functionality.
|
9
|
+
module Entities
|
10
|
+
autoload :Attributes, 'stannum/entities/attributes'
|
11
|
+
autoload :Associations, 'stannum/entities/associations'
|
12
|
+
autoload :Constraints, 'stannum/entities/constraints'
|
13
|
+
autoload :PrimaryKey, 'stannum/entities/primary_key'
|
14
|
+
autoload :Properties, 'stannum/entities/properties'
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'stannum'
|
4
|
+
require 'stannum/entities/associations'
|
5
|
+
require 'stannum/entities/attributes'
|
6
|
+
require 'stannum/entities/constraints'
|
7
|
+
require 'stannum/entities/primary_key'
|
8
|
+
require 'stannum/entities/properties'
|
9
|
+
|
10
|
+
module Stannum
|
11
|
+
# Abstract module for defining objects with structured attributes.
|
12
|
+
#
|
13
|
+
# @example Defining Attributes
|
14
|
+
# class Widget
|
15
|
+
# include Stannum::Entity
|
16
|
+
#
|
17
|
+
# attribute :name, String
|
18
|
+
# attribute :description, String, optional: true
|
19
|
+
# attribute :quantity, Integer, default: 0
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# widget = Widget.new(name: 'Self-sealing Stem Bolt')
|
23
|
+
# widget.name #=> 'Self-sealing Stem Bolt'
|
24
|
+
# widget.description #=> nil
|
25
|
+
# widget.quantity #=> 0
|
26
|
+
# widget.attributes #=>
|
27
|
+
# # {
|
28
|
+
# # name: 'Self-sealing Stem Bolt',
|
29
|
+
# # description: nil,
|
30
|
+
# # quantity: 0
|
31
|
+
# # }
|
32
|
+
#
|
33
|
+
# @example Setting Attributes
|
34
|
+
# widget.description = 'A stem bolt, but self sealing.'
|
35
|
+
# widget.attributes #=>
|
36
|
+
# # {
|
37
|
+
# # name: 'Self-sealing Stem Bolt',
|
38
|
+
# # description: 'A stem bolt, but self sealing.',
|
39
|
+
# # quantity: 0
|
40
|
+
# # }
|
41
|
+
#
|
42
|
+
# widget.assign_attributes(quantity: 50)
|
43
|
+
# widget.attributes #=>
|
44
|
+
# # {
|
45
|
+
# # name: 'Self-sealing Stem Bolt',
|
46
|
+
# # description: 'A stem bolt, but self sealing.',
|
47
|
+
# # quantity: 50
|
48
|
+
# # }
|
49
|
+
#
|
50
|
+
# widget.attributes = (name: 'Inverse Chronoton Emitter')
|
51
|
+
# # {
|
52
|
+
# # name: 'Inverse Chronoton Emitter',
|
53
|
+
# # description: nil,
|
54
|
+
# # quantity: 0
|
55
|
+
# # }
|
56
|
+
#
|
57
|
+
# @example Defining Attribute Constraints
|
58
|
+
# Widget::Contract.matches?(quantity: -5) #=> false
|
59
|
+
# Widget::Contract.matches?(name: 'Capacitor', quantity: -5) #=> true
|
60
|
+
#
|
61
|
+
# class Widget
|
62
|
+
# constraint(:quantity) { |qty| qty >= 0 }
|
63
|
+
# end
|
64
|
+
#
|
65
|
+
# Widget::Contract.matches?(name: 'Capacitor', quantity: -5) #=> false
|
66
|
+
# Widget::Contract.matches?(name: 'Capacitor', quantity: 10) #=> true
|
67
|
+
#
|
68
|
+
# @example Defining Struct Constraints
|
69
|
+
# Widget::Contract.matches?(name: 'Diode') #=> true
|
70
|
+
#
|
71
|
+
# class Widget
|
72
|
+
# constraint { |struct| struct.description&.include?(struct.name) }
|
73
|
+
# end
|
74
|
+
#
|
75
|
+
# Widget::Contract.matches?(name: 'Diode') #=> false
|
76
|
+
# Widget::Contract.matches?(
|
77
|
+
# name: 'Diode',
|
78
|
+
# description: 'A low budget Diode',
|
79
|
+
# ) #=> true
|
80
|
+
module Entity
|
81
|
+
include Stannum::Entities::Properties
|
82
|
+
include Stannum::Entities::Attributes
|
83
|
+
include Stannum::Entities::Associations
|
84
|
+
include Stannum::Entities::PrimaryKey
|
85
|
+
include Stannum::Entities::Constraints
|
86
|
+
end
|
87
|
+
end
|
data/lib/stannum/errors.rb
CHANGED
@@ -326,7 +326,7 @@ module Stannum
|
|
326
326
|
# .add(:not_integer, message: 'is outside the range')
|
327
327
|
# .add(:not_in_range)
|
328
328
|
def add(type, message: nil, **data)
|
329
|
-
error = build_error(data
|
329
|
+
error = build_error(data:, message:, type:)
|
330
330
|
hashed = error.hash
|
331
331
|
|
332
332
|
return self if @cache.include?(hashed)
|
@@ -436,7 +436,7 @@ module Stannum
|
|
436
436
|
# @overload each
|
437
437
|
# Iterates through the errors, yielding each error to the provided block.
|
438
438
|
#
|
439
|
-
# @yieldparam error [Hash
|
439
|
+
# @yieldparam error [Hash{Symbol=>Object}] The error object. Each error
|
440
440
|
# is a hash containing the keys :data, :message, :path and :type.
|
441
441
|
def each
|
442
442
|
return to_enum(:each) { size } unless block_given?
|
@@ -492,7 +492,7 @@ module Stannum
|
|
492
492
|
|
493
493
|
# @return [String] a human-readable representation of the object.
|
494
494
|
def inspect
|
495
|
-
oid = super[2
|
495
|
+
oid = super[2...].split.first.split(':').last
|
496
496
|
|
497
497
|
"#<#{self.class.name}:#{oid} @summary=%{#{summary}}>"
|
498
498
|
end
|
@@ -592,14 +592,12 @@ module Stannum
|
|
592
592
|
|
593
593
|
protected
|
594
594
|
|
595
|
-
def each_error(&
|
595
|
+
def each_error(&)
|
596
596
|
return enum_for(:each_error) unless block_given?
|
597
597
|
|
598
|
-
@errors.each(&
|
598
|
+
@errors.each(&)
|
599
599
|
|
600
|
-
@children.each_value
|
601
|
-
child.each_error(&block)
|
602
|
-
end
|
600
|
+
@children.each_value { |child| child.each_error(&) }
|
603
601
|
end
|
604
602
|
|
605
603
|
def update_errors(other_errors)
|
@@ -621,10 +619,10 @@ module Stannum
|
|
621
619
|
type = normalize_type(type)
|
622
620
|
msg = normalize_message(message)
|
623
621
|
|
624
|
-
{ data
|
622
|
+
{ data:, message: msg, type: }
|
625
623
|
end
|
626
624
|
|
627
|
-
def compare_hashed_errors(other_errors)
|
625
|
+
def compare_hashed_errors(other_errors) # rubocop:disable Naming/PredicateMethod
|
628
626
|
hashes = Set.new(map(&:hash))
|
629
627
|
other_hashes = Set.new(other_errors.map(&:hash))
|
630
628
|
|
@@ -644,7 +642,7 @@ module Stannum
|
|
644
642
|
|
645
643
|
return path.first.to_s if path.size == 1
|
646
644
|
|
647
|
-
path[1
|
645
|
+
path[1..].reduce(path.first.to_s) do |str, item|
|
648
646
|
item.is_a?(Integer) ? "#{str}[#{item}]" : "#{str}.#{item}"
|
649
647
|
end
|
650
648
|
end
|
@@ -669,7 +667,7 @@ module Stannum
|
|
669
667
|
child = self.class.new
|
670
668
|
|
671
669
|
ary.each do |item|
|
672
|
-
err = normalize_array_item(item, allow_nil:
|
670
|
+
err = normalize_array_item(item, allow_nil:)
|
673
671
|
data = err.fetch(:data, {})
|
674
672
|
path = err.fetch(:path, [])
|
675
673
|
|
@@ -708,9 +706,7 @@ module Stannum
|
|
708
706
|
|
709
707
|
return value.dup if value.is_a?(self.class)
|
710
708
|
|
711
|
-
if value.is_a?(Array)
|
712
|
-
return normalize_array_value(value, allow_nil: allow_nil)
|
713
|
-
end
|
709
|
+
return normalize_array_value(value, allow_nil:) if value.is_a?(Array)
|
714
710
|
|
715
711
|
raise ArgumentError, invalid_value_error(allow_nil)
|
716
712
|
end
|
@@ -724,7 +720,7 @@ module Stannum
|
|
724
720
|
|
725
721
|
raise ArgumentError,
|
726
722
|
'key must be an Integer, a String or a Symbol',
|
727
|
-
caller(1
|
723
|
+
caller(1..)
|
728
724
|
end
|
729
725
|
end
|
730
726
|
end
|
@@ -18,7 +18,7 @@ module Stannum::Messages
|
|
18
18
|
@load_paths ||= DEFAULT_LOAD_PATHS.dup
|
19
19
|
end
|
20
20
|
|
21
|
-
# @param configuration [Hash{Symbol
|
21
|
+
# @param configuration [Hash{Symbol=>Object}] The configured messages.
|
22
22
|
# @param load_paths [Array<String>] The directories from which to load
|
23
23
|
# configured error messages.
|
24
24
|
# @param locale [String] The locale used to load and scope configured
|
@@ -97,7 +97,7 @@ module Stannum::Messages
|
|
97
97
|
Stannum::Messages::DefaultLoader
|
98
98
|
.new(
|
99
99
|
file_paths: load_paths,
|
100
|
-
locale:
|
100
|
+
locale:
|
101
101
|
)
|
102
102
|
.call
|
103
103
|
end
|
@@ -126,11 +126,11 @@ module Stannum
|
|
126
126
|
self::MethodValidations.define_method(method_name) \
|
127
127
|
do |*arguments, **keywords, &block|
|
128
128
|
result = match_parameters_to_contract(
|
129
|
-
arguments
|
130
|
-
block
|
131
|
-
contract
|
132
|
-
keywords
|
133
|
-
method_name:
|
129
|
+
arguments:,
|
130
|
+
block:,
|
131
|
+
contract:,
|
132
|
+
keywords:,
|
133
|
+
method_name:
|
134
134
|
)
|
135
135
|
|
136
136
|
return result unless result == VALIDATION_SUCCESS
|
@@ -199,17 +199,17 @@ module Stannum
|
|
199
199
|
)
|
200
200
|
match, errors = contract.match(
|
201
201
|
{
|
202
|
-
arguments
|
203
|
-
keywords
|
204
|
-
block:
|
202
|
+
arguments:,
|
203
|
+
keywords:,
|
204
|
+
block:
|
205
205
|
}
|
206
206
|
)
|
207
207
|
|
208
208
|
return VALIDATION_SUCCESS if match
|
209
209
|
|
210
210
|
handle_invalid_parameters(
|
211
|
-
errors
|
212
|
-
method_name:
|
211
|
+
errors:,
|
212
|
+
method_name:
|
213
213
|
)
|
214
214
|
end
|
215
215
|
end
|
@@ -4,8 +4,8 @@ begin
|
|
4
4
|
require 'rspec/sleeping_king_studios/matchers/core/deep_matcher'
|
5
5
|
rescue NameError
|
6
6
|
# :nocov:
|
7
|
-
Kernel.warn 'WARNING: RSpec::SleepingKingStudios is a dependency for using' \
|
8
|
-
'
|
7
|
+
Kernel.warn 'WARNING: RSpec::SleepingKingStudios is a dependency for using ' \
|
8
|
+
'the MatchErrorsMatcher or the #match_errors method.'
|
9
9
|
# :nocov:
|
10
10
|
end
|
11
11
|
|
@@ -27,7 +27,7 @@ module Stannum::RSpec
|
|
27
27
|
end
|
28
28
|
|
29
29
|
# Checks that the given errors do not match the expected errors.
|
30
|
-
def does_not_match?(actual)
|
30
|
+
def does_not_match?(actual) # rubocop:disable Naming/PredicatePrefix
|
31
31
|
@actual = actual.is_a?(Stannum::Errors) ? actual.to_a : actual
|
32
32
|
|
33
33
|
errors? && equality_matcher.does_not_match?(@actual)
|
@@ -40,8 +40,8 @@ module Stannum::RSpec
|
|
40
40
|
# @return [String] a summary message describing a failed expectation.
|
41
41
|
def failure_message
|
42
42
|
unless errors?
|
43
|
-
return 'expected the errors to match the expected errors, but the' \
|
44
|
-
'
|
43
|
+
return 'expected the errors to match the expected errors, but the ' \
|
44
|
+
'object is not an array or Errors object'
|
45
45
|
end
|
46
46
|
|
47
47
|
equality_matcher.failure_message
|
@@ -51,8 +51,8 @@ module Stannum::RSpec
|
|
51
51
|
# expectation.
|
52
52
|
def failure_message_when_negated
|
53
53
|
unless errors?
|
54
|
-
return 'expected the errors not to match the expected errors, but
|
55
|
-
' object is not an array or Errors object'
|
54
|
+
return 'expected the errors not to match the expected errors, but ' \
|
55
|
+
'the object is not an array or Errors object'
|
56
56
|
end
|
57
57
|
|
58
58
|
equality_matcher.failure_message_when_negated
|
@@ -15,8 +15,8 @@ module Stannum::RSpec
|
|
15
15
|
# @return [Stannum::RSpec::ValidateParameterMatcher] the matcher.
|
16
16
|
def validate_parameter(method_name, parameter_name)
|
17
17
|
Stannum::RSpec::ValidateParameterMatcher.new(
|
18
|
-
method_name
|
19
|
-
parameter_name:
|
18
|
+
method_name:,
|
19
|
+
parameter_name:
|
20
20
|
)
|
21
21
|
end
|
22
22
|
end
|
@@ -18,13 +18,21 @@ module Stannum::RSpec
|
|
18
18
|
class InvalidParameterHandledError < StandardError; end
|
19
19
|
private_constant :InvalidParameterHandledError
|
20
20
|
|
21
|
+
EXTRA_PARAMETER_ERROR_TYPES = Set.new(
|
22
|
+
[
|
23
|
+
Stannum::Constraints::Parameters::ExtraArguments::TYPE,
|
24
|
+
Stannum::Constraints::Parameters::ExtraKeywords::TYPE
|
25
|
+
]
|
26
|
+
).freeze
|
27
|
+
private_constant :EXTRA_PARAMETER_ERROR_TYPES
|
28
|
+
|
21
29
|
class << self
|
22
30
|
# @private
|
23
31
|
def add_parameter_mapping(map:, match:)
|
24
32
|
raise ArgumentError, 'map must be a Proc' unless map.is_a?(Proc)
|
25
33
|
raise ArgumentError, 'match must be a Proc' unless match.is_a?(Proc)
|
26
34
|
|
27
|
-
parameter_mappings << { match
|
35
|
+
parameter_mappings << { match:, map: }
|
28
36
|
end
|
29
37
|
|
30
38
|
# @private
|
@@ -33,12 +41,12 @@ module Stannum::RSpec
|
|
33
41
|
match = keywords.fetch(:match)
|
34
42
|
map = keywords.fetch(:map)
|
35
43
|
|
36
|
-
next unless match.call(actual
|
44
|
+
next unless match.call(actual:, method_name:)
|
37
45
|
|
38
|
-
return map.call(actual
|
46
|
+
return map.call(actual:, method_name:)
|
39
47
|
end
|
40
48
|
|
41
|
-
unwrapped_method(actual
|
49
|
+
unwrapped_method(actual:, method_name:).parameters
|
42
50
|
end
|
43
51
|
|
44
52
|
private
|
@@ -109,7 +117,7 @@ module Stannum::RSpec
|
|
109
117
|
#
|
110
118
|
# @return [true, false] false if the object validates the parameter,
|
111
119
|
# otherwise true.
|
112
|
-
def does_not_match?(actual)
|
120
|
+
def does_not_match?(actual) # rubocop:disable Naming/PredicatePrefix
|
113
121
|
disallow_fluent_options!
|
114
122
|
|
115
123
|
@actual = actual
|
@@ -139,11 +147,11 @@ module Stannum::RSpec
|
|
139
147
|
when :method_does_not_have_parameter
|
140
148
|
"##{method_name} does not have a #{parameter_name.inspect} parameter"
|
141
149
|
when :parameter_not_validated
|
142
|
-
"##{method_name} does not expect a #{parameter_name.inspect}" \
|
143
|
-
"
|
150
|
+
"##{method_name} does not expect a #{parameter_name.inspect} " \
|
151
|
+
"#{parameter_type}"
|
144
152
|
when :valid_parameter_value
|
145
|
-
"#{valid_value.inspect} is a valid value for the" \
|
146
|
-
"
|
153
|
+
"#{valid_value.inspect} is a valid value for the " \
|
154
|
+
"#{parameter_name.inspect} #{parameter_type}"
|
147
155
|
end
|
148
156
|
|
149
157
|
[message, reason].compact.join(', but ')
|
@@ -281,20 +289,20 @@ module Stannum::RSpec
|
|
281
289
|
unless @expected_constraint.nil?
|
282
290
|
raise RuntimeError,
|
283
291
|
'#does_not_match? with #using_constraint is not supported',
|
284
|
-
caller[1
|
292
|
+
caller[1..]
|
285
293
|
end
|
286
294
|
|
287
295
|
unless @parameters.nil?
|
288
296
|
raise RuntimeError,
|
289
297
|
'#does_not_match? with #with_parameters is not supported',
|
290
|
-
caller[1
|
298
|
+
caller[1..]
|
291
299
|
end
|
292
300
|
|
293
301
|
return if @parameter_value.nil?
|
294
302
|
|
295
303
|
raise RuntimeError,
|
296
304
|
'#does_not_match? with #with_value is not supported',
|
297
|
-
caller[1
|
305
|
+
caller[1..]
|
298
306
|
end
|
299
307
|
|
300
308
|
def equality_matcher
|
@@ -313,14 +321,8 @@ module Stannum::RSpec
|
|
313
321
|
end
|
314
322
|
|
315
323
|
def extra_parameter?
|
316
|
-
extra_arguments_type =
|
317
|
-
Stannum::Constraints::Parameters::ExtraArguments::TYPE
|
318
|
-
extra_keywords_type =
|
319
|
-
Stannum::Constraints::Parameters::ExtraKeywords::TYPE
|
320
|
-
|
321
324
|
return false unless scoped_errors(indexed: true).any? do |error|
|
322
|
-
error[:type]
|
323
|
-
error[:type] == extra_keywords_type
|
325
|
+
EXTRA_PARAMETER_ERROR_TYPES.include?(error[:type])
|
324
326
|
end
|
325
327
|
|
326
328
|
@failure_reason = :parameter_not_validated
|
@@ -372,7 +374,7 @@ module Stannum::RSpec
|
|
372
374
|
|
373
375
|
def method_parameters
|
374
376
|
@method_parameters ||=
|
375
|
-
self.class.map_parameters(actual
|
377
|
+
self.class.map_parameters(actual:, method_name:)
|
376
378
|
end
|
377
379
|
|
378
380
|
def mock_validation_handler
|