dry-logic 0.6.0 → 1.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +2 -5
- data/.github/ISSUE_TEMPLATE/----please-don-t-ask-for-support-via-issues.md +10 -0
- data/.github/ISSUE_TEMPLATE/---bug-report.md +34 -0
- data/.github/ISSUE_TEMPLATE/---feature-request.md +18 -0
- data/.github/workflows/ci.yml +70 -0
- data/.github/workflows/docsite.yml +34 -0
- data/.github/workflows/sync_configs.yml +34 -0
- data/.gitignore +2 -1
- data/.rspec +1 -0
- data/.rubocop.yml +89 -0
- data/CHANGELOG.md +51 -2
- data/CODE_OF_CONDUCT.md +13 -0
- data/CONTRIBUTING.md +3 -3
- data/Gemfile +3 -0
- data/LICENSE +1 -1
- data/README.md +7 -7
- data/Rakefile +2 -0
- data/benchmarks/rule_application.rb +2 -0
- data/benchmarks/setup.rb +2 -0
- data/bin/console +1 -0
- data/docsite/source/index.html.md +54 -0
- data/docsite/source/operations.html.md +62 -0
- data/docsite/source/predicates.html.md +102 -0
- data/dry-logic.gemspec +8 -0
- data/examples/basic.rb +2 -0
- data/lib/dry-logic.rb +2 -0
- data/lib/dry/logic.rb +2 -0
- data/lib/dry/logic/appliable.rb +2 -0
- data/lib/dry/logic/evaluator.rb +2 -0
- data/lib/dry/logic/operations.rb +2 -0
- data/lib/dry/logic/operations/abstract.rb +5 -3
- data/lib/dry/logic/operations/and.rb +3 -1
- data/lib/dry/logic/operations/attr.rb +2 -0
- data/lib/dry/logic/operations/binary.rb +2 -0
- data/lib/dry/logic/operations/check.rb +3 -1
- data/lib/dry/logic/operations/each.rb +2 -0
- data/lib/dry/logic/operations/implication.rb +2 -0
- data/lib/dry/logic/operations/key.rb +4 -2
- data/lib/dry/logic/operations/negation.rb +2 -0
- data/lib/dry/logic/operations/or.rb +2 -0
- data/lib/dry/logic/operations/set.rb +2 -0
- data/lib/dry/logic/operations/unary.rb +2 -0
- data/lib/dry/logic/operations/xor.rb +2 -0
- data/lib/dry/logic/operators.rb +2 -0
- data/lib/dry/logic/predicates.rb +39 -21
- data/lib/dry/logic/result.rb +2 -0
- data/lib/dry/logic/rule.rb +5 -3
- data/lib/dry/logic/rule/interface.rb +20 -0
- data/lib/dry/logic/rule/predicate.rb +2 -0
- data/lib/dry/logic/rule_compiler.rb +2 -0
- data/lib/dry/logic/version.rb +3 -1
- data/spec/integration/result_spec.rb +2 -0
- data/spec/integration/rule_spec.rb +2 -0
- data/spec/shared/predicates.rb +2 -0
- data/spec/shared/rule.rb +2 -0
- data/spec/spec_helper.rb +6 -10
- data/spec/support/mutant.rb +2 -0
- data/spec/unit/operations/and_spec.rb +2 -0
- data/spec/unit/operations/attr_spec.rb +2 -0
- data/spec/unit/operations/check_spec.rb +2 -0
- data/spec/unit/operations/each_spec.rb +2 -0
- data/spec/unit/operations/implication_spec.rb +2 -0
- data/spec/unit/operations/key_spec.rb +2 -0
- data/spec/unit/operations/negation_spec.rb +2 -0
- data/spec/unit/operations/or_spec.rb +2 -0
- data/spec/unit/operations/set_spec.rb +2 -0
- data/spec/unit/operations/xor_spec.rb +2 -0
- data/spec/unit/predicates/array_spec.rb +2 -0
- data/spec/unit/predicates/attr_spec.rb +2 -0
- data/spec/unit/predicates/bool_spec.rb +3 -1
- data/spec/unit/predicates/bytesize_spec.rb +48 -0
- data/spec/unit/predicates/case_spec.rb +2 -0
- data/spec/unit/predicates/date_spec.rb +2 -0
- data/spec/unit/predicates/date_time_spec.rb +3 -1
- data/spec/unit/predicates/decimal_spec.rb +3 -1
- data/spec/unit/predicates/empty_spec.rb +2 -0
- data/spec/unit/predicates/eql_spec.rb +2 -0
- data/spec/unit/predicates/even_spec.rb +2 -0
- data/spec/unit/predicates/excluded_from_spec.rb +2 -0
- data/spec/unit/predicates/excludes_spec.rb +2 -0
- data/spec/unit/predicates/false_spec.rb +3 -1
- data/spec/unit/predicates/filled_spec.rb +2 -0
- data/spec/unit/predicates/float_spec.rb +2 -0
- data/spec/unit/predicates/format_spec.rb +2 -0
- data/spec/unit/predicates/gt_spec.rb +2 -0
- data/spec/unit/predicates/gteq_spec.rb +2 -0
- data/spec/unit/predicates/hash_spec.rb +40 -0
- data/spec/unit/predicates/included_in_spec.rb +2 -0
- data/spec/unit/predicates/int_spec.rb +2 -0
- data/spec/unit/predicates/key_spec.rb +2 -0
- data/spec/unit/predicates/lt_spec.rb +2 -0
- data/spec/unit/predicates/lteq_spec.rb +2 -0
- data/spec/unit/predicates/max_bytesize_spec.rb +39 -0
- data/spec/unit/predicates/max_size_spec.rb +2 -0
- data/spec/unit/predicates/min_bytesize_spec.rb +39 -0
- data/spec/unit/predicates/min_size_spec.rb +2 -0
- data/spec/unit/predicates/none_spec.rb +2 -0
- data/spec/unit/predicates/not_eql_spec.rb +2 -0
- data/spec/unit/predicates/number_spec.rb +2 -0
- data/spec/unit/predicates/odd_spec.rb +2 -0
- data/spec/unit/predicates/respond_to_spec.rb +31 -0
- data/spec/unit/predicates/size_spec.rb +2 -0
- data/spec/unit/predicates/str_spec.rb +2 -0
- data/spec/unit/predicates/time_spec.rb +3 -1
- data/spec/unit/predicates/true_spec.rb +3 -1
- data/spec/unit/predicates/type_spec.rb +2 -0
- data/spec/unit/predicates/uuid_v4_spec.rb +29 -0
- data/spec/unit/predicates_spec.rb +2 -0
- data/spec/unit/rule/predicate_spec.rb +2 -0
- data/spec/unit/rule_compiler_spec.rb +2 -0
- data/spec/unit/rule_spec.rb +14 -3
- metadata +30 -6
- data/.travis.yml +0 -31
data/lib/dry/logic/operators.rb
CHANGED
data/lib/dry/logic/predicates.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'bigdecimal'
|
2
4
|
require 'bigdecimal/util'
|
3
5
|
require 'date'
|
@@ -57,11 +59,9 @@ module Dry
|
|
57
59
|
end
|
58
60
|
|
59
61
|
def number?(input)
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
false
|
64
|
-
end
|
62
|
+
true if Float(input)
|
63
|
+
rescue ArgumentError, TypeError
|
64
|
+
false
|
65
65
|
end
|
66
66
|
|
67
67
|
def int?(input)
|
@@ -114,7 +114,7 @@ module Dry
|
|
114
114
|
|
115
115
|
def size?(size, input)
|
116
116
|
case size
|
117
|
-
when Integer then size
|
117
|
+
when Integer then size.equal?(input.size)
|
118
118
|
when Range, Array then size.include?(input.size)
|
119
119
|
else
|
120
120
|
raise ArgumentError, "+#{size}+ is not supported type for size? predicate."
|
@@ -129,6 +129,23 @@ module Dry
|
|
129
129
|
input.size <= num
|
130
130
|
end
|
131
131
|
|
132
|
+
def bytesize?(size, input)
|
133
|
+
case size
|
134
|
+
when Integer then size.equal?(input.bytesize)
|
135
|
+
when Range, Array then size.include?(input.bytesize)
|
136
|
+
else
|
137
|
+
raise ArgumentError, "+#{size}+ is not supported type for bytesize? predicate."
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def min_bytesize?(num, input)
|
142
|
+
input.bytesize >= num
|
143
|
+
end
|
144
|
+
|
145
|
+
def max_bytesize?(num, input)
|
146
|
+
input.bytesize <= num
|
147
|
+
end
|
148
|
+
|
132
149
|
def inclusion?(list, input)
|
133
150
|
::Kernel.warn 'inclusion is deprecated - use included_in instead.'
|
134
151
|
included_in?(list, input)
|
@@ -148,15 +165,13 @@ module Dry
|
|
148
165
|
end
|
149
166
|
|
150
167
|
def includes?(value, input)
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
else
|
155
|
-
false
|
156
|
-
end
|
157
|
-
rescue TypeError
|
168
|
+
if input.respond_to?(:include?)
|
169
|
+
input.include?(value)
|
170
|
+
else
|
158
171
|
false
|
159
172
|
end
|
173
|
+
rescue TypeError
|
174
|
+
false
|
160
175
|
end
|
161
176
|
|
162
177
|
def excludes?(value, input)
|
@@ -183,20 +198,23 @@ module Dry
|
|
183
198
|
value.equal?(false)
|
184
199
|
end
|
185
200
|
|
186
|
-
|
187
|
-
|
188
|
-
!regex.match(input).nil?
|
189
|
-
end
|
190
|
-
else
|
191
|
-
def format?(regex, input)
|
192
|
-
regex.match?(input)
|
193
|
-
end
|
201
|
+
def format?(regex, input)
|
202
|
+
regex.match?(input)
|
194
203
|
end
|
195
204
|
|
196
205
|
def case?(pattern, input)
|
197
206
|
pattern === input
|
198
207
|
end
|
199
208
|
|
209
|
+
def uuid_v4?(input)
|
210
|
+
uuid_v4_format = /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
|
211
|
+
format?(uuid_v4_format, input)
|
212
|
+
end
|
213
|
+
|
214
|
+
def respond_to?(method, input)
|
215
|
+
input.respond_to?(method)
|
216
|
+
end
|
217
|
+
|
200
218
|
def predicate(name, &block)
|
201
219
|
define_singleton_method(name, &block)
|
202
220
|
end
|
data/lib/dry/logic/result.rb
CHANGED
data/lib/dry/logic/rule.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'concurrent/map'
|
2
4
|
require 'dry/core/constants'
|
3
5
|
require 'dry/equalizer'
|
@@ -66,11 +68,11 @@ module Dry
|
|
66
68
|
|
67
69
|
def bind(object)
|
68
70
|
if predicate.respond_to?(:bind)
|
69
|
-
self.class.build(predicate.bind(object), options)
|
71
|
+
self.class.build(predicate.bind(object), **options)
|
70
72
|
else
|
71
73
|
self.class.build(
|
72
74
|
-> *args { object.instance_exec(*args, &predicate) },
|
73
|
-
options
|
75
|
+
**options, arity: arity, parameters: parameters
|
74
76
|
)
|
75
77
|
end
|
76
78
|
end
|
@@ -80,7 +82,7 @@ module Dry
|
|
80
82
|
end
|
81
83
|
|
82
84
|
def with(new_opts)
|
83
|
-
self.class.build(predicate, options
|
85
|
+
self.class.build(predicate, **options, **new_opts)
|
84
86
|
end
|
85
87
|
|
86
88
|
def parameters
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Dry
|
2
4
|
module Logic
|
3
5
|
class Rule
|
@@ -18,6 +20,8 @@ module Dry
|
|
18
20
|
|
19
21
|
if variable_arity?
|
20
22
|
define_splat_application
|
23
|
+
elsif constant?
|
24
|
+
define_constant_application
|
21
25
|
else
|
22
26
|
define_fixed_application
|
23
27
|
end
|
@@ -71,6 +75,22 @@ module Dry
|
|
71
75
|
RUBY
|
72
76
|
end
|
73
77
|
|
78
|
+
def define_constant_application
|
79
|
+
module_exec do
|
80
|
+
def call(*)
|
81
|
+
if @predicate[]
|
82
|
+
Result::SUCCESS
|
83
|
+
else
|
84
|
+
Result.new(false, id) { ast }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def [](*)
|
89
|
+
@predicate[]
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
74
94
|
def define_splat_application
|
75
95
|
application =
|
76
96
|
if curried?
|
data/lib/dry/logic/version.rb
CHANGED
data/spec/shared/predicates.rb
CHANGED
data/spec/shared/rule.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -1,13 +1,9 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
require 'simplecov'
|
8
|
-
SimpleCov.start do
|
9
|
-
add_filter '/spec/'
|
10
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
if ENV['COVERAGE'] == 'true'
|
4
|
+
require 'simplecov'
|
5
|
+
SimpleCov.start do
|
6
|
+
add_filter '/spec/'
|
11
7
|
end
|
12
8
|
end
|
13
9
|
|
data/spec/support/mutant.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'dry/logic/predicates'
|
2
4
|
|
3
5
|
RSpec.describe Dry::Logic::Predicates do
|
4
6
|
describe '#bool?' do
|
5
7
|
let(:predicate_name) { :bool? }
|
6
8
|
|
7
|
-
context 'when value is a
|
9
|
+
context 'when value is a boolean' do
|
8
10
|
let(:arguments_list) do
|
9
11
|
[[true], [false]]
|
10
12
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'dry/logic/predicates'
|
4
|
+
|
5
|
+
RSpec.describe Dry::Logic::Predicates do
|
6
|
+
describe '#bytesize?' do
|
7
|
+
let(:predicate_name) { :bytesize? }
|
8
|
+
|
9
|
+
context 'when value size is equal to n' do
|
10
|
+
let(:arguments_list) do
|
11
|
+
[
|
12
|
+
[4, 'こa'],
|
13
|
+
[1..8, 'こa']
|
14
|
+
]
|
15
|
+
end
|
16
|
+
|
17
|
+
it_behaves_like 'a passing predicate'
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'when value size is greater than n' do
|
21
|
+
let(:arguments_list) do
|
22
|
+
[
|
23
|
+
[3, 'こa'],
|
24
|
+
[1..3, 'こa']
|
25
|
+
]
|
26
|
+
end
|
27
|
+
|
28
|
+
it_behaves_like 'a failing predicate'
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'with value size is less than n' do
|
32
|
+
let(:arguments_list) do
|
33
|
+
[
|
34
|
+
[5, 'こa'],
|
35
|
+
[5..10, 'こa']
|
36
|
+
]
|
37
|
+
end
|
38
|
+
|
39
|
+
it_behaves_like 'a failing predicate'
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'with an unsupported size' do
|
43
|
+
it 'raises an error' do
|
44
|
+
expect { Predicates[:bytesize?].call('oops', 1) }.to raise_error(ArgumentError, /oops/)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|