stannum 0.1.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 +7 -0
- data/CHANGELOG.md +21 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/DEVELOPMENT.md +105 -0
- data/LICENSE +22 -0
- data/README.md +1327 -0
- data/config/locales/en.rb +47 -0
- data/lib/stannum/attribute.rb +115 -0
- data/lib/stannum/constraint.rb +65 -0
- data/lib/stannum/constraints/absence.rb +42 -0
- data/lib/stannum/constraints/anything.rb +28 -0
- data/lib/stannum/constraints/base.rb +285 -0
- data/lib/stannum/constraints/boolean.rb +33 -0
- data/lib/stannum/constraints/delegator.rb +71 -0
- data/lib/stannum/constraints/enum.rb +64 -0
- data/lib/stannum/constraints/equality.rb +47 -0
- data/lib/stannum/constraints/hashes/extra_keys.rb +126 -0
- data/lib/stannum/constraints/hashes/indifferent_key.rb +74 -0
- data/lib/stannum/constraints/hashes.rb +11 -0
- data/lib/stannum/constraints/identity.rb +46 -0
- data/lib/stannum/constraints/nothing.rb +28 -0
- data/lib/stannum/constraints/presence.rb +42 -0
- data/lib/stannum/constraints/signature.rb +92 -0
- data/lib/stannum/constraints/signatures/map.rb +17 -0
- data/lib/stannum/constraints/signatures/tuple.rb +17 -0
- data/lib/stannum/constraints/signatures.rb +11 -0
- data/lib/stannum/constraints/tuples/extra_items.rb +84 -0
- data/lib/stannum/constraints/tuples.rb +10 -0
- data/lib/stannum/constraints/type.rb +113 -0
- data/lib/stannum/constraints/types/array_type.rb +148 -0
- data/lib/stannum/constraints/types/big_decimal_type.rb +16 -0
- data/lib/stannum/constraints/types/date_time_type.rb +16 -0
- data/lib/stannum/constraints/types/date_type.rb +16 -0
- data/lib/stannum/constraints/types/float_type.rb +14 -0
- data/lib/stannum/constraints/types/hash_type.rb +205 -0
- data/lib/stannum/constraints/types/hash_with_indifferent_keys.rb +21 -0
- data/lib/stannum/constraints/types/hash_with_string_keys.rb +21 -0
- data/lib/stannum/constraints/types/hash_with_symbol_keys.rb +21 -0
- data/lib/stannum/constraints/types/integer_type.rb +14 -0
- data/lib/stannum/constraints/types/nil_type.rb +20 -0
- data/lib/stannum/constraints/types/proc_type.rb +14 -0
- data/lib/stannum/constraints/types/string_type.rb +14 -0
- data/lib/stannum/constraints/types/symbol_type.rb +14 -0
- data/lib/stannum/constraints/types/time_type.rb +14 -0
- data/lib/stannum/constraints/types.rb +25 -0
- data/lib/stannum/constraints/union.rb +85 -0
- data/lib/stannum/constraints.rb +26 -0
- data/lib/stannum/contract.rb +243 -0
- data/lib/stannum/contracts/array_contract.rb +108 -0
- data/lib/stannum/contracts/base.rb +597 -0
- data/lib/stannum/contracts/builder.rb +72 -0
- data/lib/stannum/contracts/definition.rb +74 -0
- data/lib/stannum/contracts/hash_contract.rb +136 -0
- data/lib/stannum/contracts/indifferent_hash_contract.rb +78 -0
- data/lib/stannum/contracts/map_contract.rb +199 -0
- data/lib/stannum/contracts/parameters/arguments_contract.rb +185 -0
- data/lib/stannum/contracts/parameters/keywords_contract.rb +174 -0
- data/lib/stannum/contracts/parameters/signature_contract.rb +29 -0
- data/lib/stannum/contracts/parameters.rb +15 -0
- data/lib/stannum/contracts/parameters_contract.rb +530 -0
- data/lib/stannum/contracts/tuple_contract.rb +213 -0
- data/lib/stannum/contracts.rb +19 -0
- data/lib/stannum/errors.rb +730 -0
- data/lib/stannum/messages/default_strategy.rb +124 -0
- data/lib/stannum/messages.rb +25 -0
- data/lib/stannum/parameter_validation.rb +216 -0
- data/lib/stannum/rspec/match_errors.rb +17 -0
- data/lib/stannum/rspec/match_errors_matcher.rb +93 -0
- data/lib/stannum/rspec/validate_parameter.rb +23 -0
- data/lib/stannum/rspec/validate_parameter_matcher.rb +506 -0
- data/lib/stannum/rspec.rb +8 -0
- data/lib/stannum/schema.rb +131 -0
- data/lib/stannum/struct.rb +444 -0
- data/lib/stannum/support/coercion.rb +114 -0
- data/lib/stannum/support/optional.rb +69 -0
- data/lib/stannum/support.rb +8 -0
- data/lib/stannum/version.rb +57 -0
- data/lib/stannum.rb +27 -0
- metadata +216 -0
@@ -0,0 +1,124 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
require 'sleeping_king_studios/tools/toolbelt'
|
6
|
+
|
7
|
+
require 'stannum/messages'
|
8
|
+
|
9
|
+
module Stannum::Messages
|
10
|
+
# Strategy to generate error messages from gem configuration.
|
11
|
+
class DefaultStrategy
|
12
|
+
# @param configuration [Hash{Symbol, Object}] The configured messages.
|
13
|
+
# @param load_path [Array<String>] The filenames for the configuration
|
14
|
+
# file(s).
|
15
|
+
def initialize(configuration: nil, load_path: nil)
|
16
|
+
@load_path = load_path.nil? ? [default_filename] : Array(load_path)
|
17
|
+
@configuration = configuration
|
18
|
+
end
|
19
|
+
|
20
|
+
# @return [Array<String>] the filenames for the configuration file(s).
|
21
|
+
attr_reader :load_path
|
22
|
+
|
23
|
+
# @param error_type [String] The qualified path to the configured error
|
24
|
+
# message.
|
25
|
+
# @param options [Hash] Additional properties to interpolate or to pass to
|
26
|
+
# the message proc.
|
27
|
+
def call(error_type, **options)
|
28
|
+
unless error_type.is_a?(String) || error_type.is_a?(Symbol)
|
29
|
+
raise ArgumentError, 'error type must be a String or Symbol'
|
30
|
+
end
|
31
|
+
|
32
|
+
message = generate_message(error_type, options)
|
33
|
+
|
34
|
+
interpolate_message(message, options)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Reloads the configuration from the configured load_path.
|
38
|
+
#
|
39
|
+
# This can be useful when the load_path is updated after creating the
|
40
|
+
# strategy, such as in an initializer for another gem.
|
41
|
+
#
|
42
|
+
# @return [DefaultStrategy] the strategy.
|
43
|
+
def reload_configuration!
|
44
|
+
@configuration = load_configuration
|
45
|
+
|
46
|
+
self
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def configuration
|
52
|
+
@configuration ||= load_configuration
|
53
|
+
end
|
54
|
+
|
55
|
+
def deep_merge(source, target)
|
56
|
+
hsh = tools.hash_tools.deep_dup(source)
|
57
|
+
|
58
|
+
target.each do |key, value|
|
59
|
+
hsh[key] = value.is_a?(Hash) ? deep_merge(hsh[key] || {}, value) : value
|
60
|
+
end
|
61
|
+
|
62
|
+
hsh
|
63
|
+
end
|
64
|
+
|
65
|
+
def default_filename
|
66
|
+
File.join(Stannum::Messages.locales_path, 'en.rb')
|
67
|
+
end
|
68
|
+
|
69
|
+
def generate_message(error_type, options)
|
70
|
+
path = error_type.to_s.split('.').map(&:intern)
|
71
|
+
path.unshift(:en)
|
72
|
+
|
73
|
+
message = configuration.dig(*path)
|
74
|
+
|
75
|
+
return message if message.is_a?(String)
|
76
|
+
|
77
|
+
return message.call(error_type, options) if message.is_a?(Proc)
|
78
|
+
|
79
|
+
return "no message defined for #{error_type.inspect}" if message.nil?
|
80
|
+
|
81
|
+
"configuration is a namespace at #{error_type}"
|
82
|
+
end
|
83
|
+
|
84
|
+
def interpolate_message(message, options)
|
85
|
+
message.gsub(/%{\w+}/) do |match|
|
86
|
+
key = match[2..-2].intern
|
87
|
+
|
88
|
+
options.fetch(key, match)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def load_configuration
|
93
|
+
load_path.reduce({}) do |config, filename|
|
94
|
+
deep_merge(config, read_configuration(filename))
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def read_configuration(filename)
|
99
|
+
case File.extname(filename)
|
100
|
+
when '.rb'
|
101
|
+
read_ruby_file(filename)
|
102
|
+
when '.yml'
|
103
|
+
read_yaml_file(filename)
|
104
|
+
else
|
105
|
+
raise "unable to load configuration file #{filename} with extension" \
|
106
|
+
" #{File.extname(filename)}"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def read_ruby_file(filename)
|
111
|
+
eval(File.read(filename), binding, filename) # rubocop:disable Security/Eval
|
112
|
+
end
|
113
|
+
|
114
|
+
def read_yaml_file(filename)
|
115
|
+
tools.hash_tools.convert_keys_to_symbols(
|
116
|
+
YAML.safe_load(File.read(filename))
|
117
|
+
)
|
118
|
+
end
|
119
|
+
|
120
|
+
def tools
|
121
|
+
SleepingKingStudios::Tools::Toolbelt.instance
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'stannum'
|
4
|
+
|
5
|
+
module Stannum
|
6
|
+
# Namespace for generating messages for Stannum::Errors.
|
7
|
+
module Messages
|
8
|
+
autoload :DefaultStrategy, 'stannum/messages/default_strategy'
|
9
|
+
|
10
|
+
# @return [String] the absolute path to the configured locales.
|
11
|
+
def self.locales_path
|
12
|
+
File.join(Stannum.gem_path, 'config', 'locales')
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [#call] the configured strategy for generating messages.
|
16
|
+
def self.strategy
|
17
|
+
@strategy ||= DefaultStrategy.new
|
18
|
+
end
|
19
|
+
|
20
|
+
# @param strategy [#call] The strategy to use to generate error messages.
|
21
|
+
def self.strategy=(strategy)
|
22
|
+
@strategy = strategy
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,216 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'stannum'
|
4
|
+
|
5
|
+
module Stannum
|
6
|
+
# Provides a DSL for validating method parameters.
|
7
|
+
#
|
8
|
+
# Use the .validate_parameters method to define parameter validation for an
|
9
|
+
# instance method of the class or module.
|
10
|
+
#
|
11
|
+
# Ruby does not distinguish between an explicit nil versus an undefined value
|
12
|
+
# in an Array or Hash, but does distinguish between a nil value and a missing
|
13
|
+
# parameter. Be careful when validating methods with optional or default
|
14
|
+
# arguments or keywords:
|
15
|
+
#
|
16
|
+
# * If the actual value can be nil, or if the default parameter is nil, then
|
17
|
+
# use the optional: true option. This will match an empty arguments list, or
|
18
|
+
# an arguments list with nil as the first value:
|
19
|
+
#
|
20
|
+
# def method_with_optional_argument(name: nil)
|
21
|
+
# @name = name || 'Alan Bradley'
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# validate_parameters(:method_with_optional_argument) do
|
25
|
+
# argument :name, optional: true
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# * If the default parameter is any other value, then use the default: true
|
29
|
+
# option. This will match an empty arguments list, but not an arguments list
|
30
|
+
# with nil as the first value:
|
31
|
+
#
|
32
|
+
# def method_with_default_argument(role: 'User')
|
33
|
+
# @role = role
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# validate_parameters(:method_with_default_argument) do
|
37
|
+
# argument :role, default: true
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# @example Validating Parameters
|
41
|
+
# class PerformAction
|
42
|
+
# include Stannum::ParameterValidation
|
43
|
+
#
|
44
|
+
# def perform(action, record_class = nil, user:, role: 'User')
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# validate_parameters(:perform) do
|
48
|
+
# argument :action, Symbol
|
49
|
+
# argument :record_class, Class, optional: true
|
50
|
+
# keyword :role, String, default: true
|
51
|
+
# keyword :user, Stannum::Constraints::Type.new(User)
|
52
|
+
# end
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# @example Validating Class Methods
|
56
|
+
# module Authorization
|
57
|
+
# extend Stannum::ParameterValidation
|
58
|
+
#
|
59
|
+
# class << self
|
60
|
+
# def authorize_user(user, role: 'User')
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
# validate_parameters(:authorize_user) do
|
64
|
+
# argument :user, User
|
65
|
+
# argument :role, String, default: true
|
66
|
+
# end
|
67
|
+
# end
|
68
|
+
# end
|
69
|
+
#
|
70
|
+
# @see Stannum::Contracts::ParametersContract.
|
71
|
+
module ParameterValidation
|
72
|
+
# @api private
|
73
|
+
#
|
74
|
+
# Value used to indicate a successful validation of the parameters.
|
75
|
+
VALIDATION_SUCCESS = Object.new.freeze
|
76
|
+
|
77
|
+
# @api private
|
78
|
+
#
|
79
|
+
# Base class for modules that handle tracking validated methods.
|
80
|
+
class MethodValidations < Module
|
81
|
+
def initialize
|
82
|
+
super
|
83
|
+
|
84
|
+
@contracts = {}
|
85
|
+
end
|
86
|
+
|
87
|
+
# @private
|
88
|
+
def add_contract(method_name, contract)
|
89
|
+
@contracts[method_name] = contract
|
90
|
+
end
|
91
|
+
|
92
|
+
# @return [Hash] the validation contracts defined for the class.
|
93
|
+
def contracts
|
94
|
+
ancestors
|
95
|
+
.select do |ancestor|
|
96
|
+
ancestor.is_a? Stannum::ParameterValidation::MethodValidations
|
97
|
+
end
|
98
|
+
.map(&:own_contracts)
|
99
|
+
.reduce(:merge)
|
100
|
+
end
|
101
|
+
|
102
|
+
# @private
|
103
|
+
def own_contracts
|
104
|
+
@contracts
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Defines a DSL for validating method parameters.
|
109
|
+
#
|
110
|
+
# @see ParameterValidation.
|
111
|
+
module ClassMethods
|
112
|
+
# rubocop:disable Metrics/MethodLength
|
113
|
+
|
114
|
+
# Creates a validation contract and wraps the named method.
|
115
|
+
#
|
116
|
+
# The provided block is used to create a ParametersContract, and supports
|
117
|
+
# the same DSL used to define one.
|
118
|
+
#
|
119
|
+
# @see Stannum::Contracts::ParametersContract
|
120
|
+
def validate_parameters(method_name, &validations)
|
121
|
+
method_name = method_name.intern
|
122
|
+
contract = Stannum::Contracts::ParametersContract.new(&validations)
|
123
|
+
|
124
|
+
self::MethodValidations.add_contract(method_name, contract)
|
125
|
+
|
126
|
+
self::MethodValidations.define_method(method_name) \
|
127
|
+
do |*arguments, **keywords, &block|
|
128
|
+
result = match_parameters_to_contract(
|
129
|
+
arguments: arguments,
|
130
|
+
block: block,
|
131
|
+
contract: contract,
|
132
|
+
keywords: keywords,
|
133
|
+
method_name: method_name
|
134
|
+
)
|
135
|
+
|
136
|
+
return result unless result == VALIDATION_SUCCESS
|
137
|
+
|
138
|
+
if keywords.empty?
|
139
|
+
super(*arguments, &block)
|
140
|
+
else
|
141
|
+
super(*arguments, **keywords, &block)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
# rubocop:enable Metrics/MethodLength
|
146
|
+
|
147
|
+
private
|
148
|
+
|
149
|
+
def inherited(subclass)
|
150
|
+
super
|
151
|
+
|
152
|
+
Stannum::ParameterValidation.add_method_validations(subclass)
|
153
|
+
|
154
|
+
subclass::MethodValidations.include(self::MethodValidations)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
class << self
|
159
|
+
# @private
|
160
|
+
def add_method_validations(other)
|
161
|
+
other.extend(ClassMethods)
|
162
|
+
|
163
|
+
validations = MethodValidations.new
|
164
|
+
|
165
|
+
other.const_set(:MethodValidations, validations)
|
166
|
+
other.prepend(validations)
|
167
|
+
end
|
168
|
+
|
169
|
+
private
|
170
|
+
|
171
|
+
def extended(other)
|
172
|
+
super
|
173
|
+
|
174
|
+
add_method_validations(other.singleton_class)
|
175
|
+
end
|
176
|
+
|
177
|
+
def included(other)
|
178
|
+
super
|
179
|
+
|
180
|
+
add_method_validations(other)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
private
|
185
|
+
|
186
|
+
def handle_invalid_parameters(errors:, method_name:)
|
187
|
+
error_message = "invalid parameters for ##{method_name}"
|
188
|
+
error_message += ": #{errors.summary}" unless errors.empty?
|
189
|
+
|
190
|
+
raise ArgumentError, error_message
|
191
|
+
end
|
192
|
+
|
193
|
+
def match_parameters_to_contract( # rubocop:disable Metrics/MethodLength
|
194
|
+
contract:,
|
195
|
+
method_name:,
|
196
|
+
arguments: [],
|
197
|
+
block: nil,
|
198
|
+
keywords: {}
|
199
|
+
)
|
200
|
+
match, errors = contract.match(
|
201
|
+
{
|
202
|
+
arguments: arguments,
|
203
|
+
keywords: keywords,
|
204
|
+
block: block
|
205
|
+
}
|
206
|
+
)
|
207
|
+
|
208
|
+
return VALIDATION_SUCCESS if match
|
209
|
+
|
210
|
+
handle_invalid_parameters(
|
211
|
+
errors: errors,
|
212
|
+
method_name: method_name
|
213
|
+
)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'stannum/rspec/match_errors_matcher'
|
4
|
+
|
5
|
+
module Stannum::RSpec
|
6
|
+
# Namespace for custom RSpec matcher macros.
|
7
|
+
module Matchers
|
8
|
+
# Builds a MatchErrorsMatcher.
|
9
|
+
#
|
10
|
+
# @param expected [Stannum::Errors] The expected errors.
|
11
|
+
#
|
12
|
+
# @return [Stannum::RSpec::MatchErrorsMatcher] the matcher.
|
13
|
+
def match_errors(expected)
|
14
|
+
Stannum::RSpec::MatchErrorsMatcher.new(expected)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'rspec/sleeping_king_studios/matchers/core/deep_matcher'
|
5
|
+
rescue NameError
|
6
|
+
# :nocov:
|
7
|
+
Kernel.warn 'WARNING: RSpec::SleepingKingStudios is a dependency for using' \
|
8
|
+
' the MatchErrorsMatcher or the #match_errors method.'
|
9
|
+
# :nocov:
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'stannum/errors'
|
13
|
+
require 'stannum/rspec'
|
14
|
+
|
15
|
+
module Stannum::RSpec
|
16
|
+
# Asserts that the expected and actual errors are equal.
|
17
|
+
class MatchErrorsMatcher
|
18
|
+
# @param expected [Stannum::Errors] The expected errors.
|
19
|
+
def initialize(expected)
|
20
|
+
@expected = expected.to_a
|
21
|
+
end
|
22
|
+
|
23
|
+
# @return [String] a short description of the matcher and expected
|
24
|
+
# properties.
|
25
|
+
def description
|
26
|
+
'match the expected errors'
|
27
|
+
end
|
28
|
+
|
29
|
+
# Checks that the given errors do not match the expected errors.
|
30
|
+
def does_not_match?(actual)
|
31
|
+
@actual = actual.is_a?(Stannum::Errors) ? actual.to_a : actual
|
32
|
+
|
33
|
+
errors? && equality_matcher.does_not_match?(@actual)
|
34
|
+
rescue NoMethodError
|
35
|
+
# :nocov:
|
36
|
+
errors? && !equality_matcher.matches?(@actual)
|
37
|
+
# :nocov:
|
38
|
+
end
|
39
|
+
|
40
|
+
# @return [String] a summary message describing a failed expectation.
|
41
|
+
def failure_message
|
42
|
+
unless errors?
|
43
|
+
return 'expected the errors to match the expected errors, but the' \
|
44
|
+
' object is not an array or Errors object'
|
45
|
+
end
|
46
|
+
|
47
|
+
equality_matcher.failure_message
|
48
|
+
end
|
49
|
+
|
50
|
+
# @return [String] a summary message describing a failed negated
|
51
|
+
# expectation.
|
52
|
+
def failure_message_when_negated
|
53
|
+
unless errors?
|
54
|
+
return 'expected the errors not to match the expected errors, but the' \
|
55
|
+
' object is not an array or Errors object'
|
56
|
+
end
|
57
|
+
|
58
|
+
equality_matcher.failure_message_when_negated
|
59
|
+
end
|
60
|
+
|
61
|
+
# Checks that the given errors match the expected errors.
|
62
|
+
#
|
63
|
+
# Returns false if the object is not a Stannum::Errors instance or an Array.
|
64
|
+
# Otherwise, it converts the expected and actual errors to arrays and
|
65
|
+
# performs a deep match.
|
66
|
+
#
|
67
|
+
# @param actual [Object] The actual object to match.
|
68
|
+
#
|
69
|
+
# @return [Boolean] true if the actual errors match the expected errors.
|
70
|
+
def matches?(actual)
|
71
|
+
@actual = actual.is_a?(Stannum::Errors) ? actual.to_a : actual
|
72
|
+
|
73
|
+
errors? && equality_matcher.matches?(@actual)
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def equality_matcher
|
79
|
+
@equality_matcher ||=
|
80
|
+
RSpec::SleepingKingStudios::Matchers::Core::DeepMatcher
|
81
|
+
.new(@expected)
|
82
|
+
rescue NameError
|
83
|
+
# :nocov:
|
84
|
+
@equality_matcher ||=
|
85
|
+
RSpec::Matchers::BuiltIn::Eq.new(@expected_errors.to_a)
|
86
|
+
# :nocov:
|
87
|
+
end
|
88
|
+
|
89
|
+
def errors?
|
90
|
+
@actual.is_a?(Stannum::Errors) || @actual.is_a?(Array)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'stannum/rspec/validate_parameter_matcher'
|
4
|
+
|
5
|
+
module Stannum::RSpec
|
6
|
+
# Namespace for custom RSpec matcher macros.
|
7
|
+
module Matchers
|
8
|
+
# Builds a ValidateParameterMatcher.
|
9
|
+
#
|
10
|
+
# @param method_name [String, Symbol] The name of the method with validated
|
11
|
+
# parameters.
|
12
|
+
# @param parameter_name [String, Symbol] The name of the validated method
|
13
|
+
# parameter.
|
14
|
+
#
|
15
|
+
# @return [Stannum::RSpec::ValidateParameterMatcher] the matcher.
|
16
|
+
def validate_parameter(method_name, parameter_name)
|
17
|
+
Stannum::RSpec::ValidateParameterMatcher.new(
|
18
|
+
method_name: method_name,
|
19
|
+
parameter_name: parameter_name
|
20
|
+
)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|