dry-logic 1.0.5 → 1.0.6
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 +76 -26
- data/LICENSE +1 -1
- data/README.md +12 -14
- data/dry-logic.gemspec +27 -20
- data/lib/dry/logic/predicates.rb +1 -1
- data/lib/dry/logic/rule/interface.rb +1 -1
- data/lib/dry/logic/version.rb +1 -1
- metadata +9 -150
- data/.codeclimate.yml +0 -12
- data/.github/ISSUE_TEMPLATE/----please-don-t-ask-for-support-via-issues.md +0 -10
- data/.github/ISSUE_TEMPLATE/---bug-report.md +0 -34
- data/.github/ISSUE_TEMPLATE/---feature-request.md +0 -18
- data/.github/workflows/ci.yml +0 -70
- data/.github/workflows/docsite.yml +0 -34
- data/.github/workflows/sync_configs.yml +0 -34
- data/.gitignore +0 -9
- data/.rspec +0 -4
- data/.rubocop.yml +0 -89
- data/CODE_OF_CONDUCT.md +0 -13
- data/CONTRIBUTING.md +0 -29
- data/Gemfile +0 -16
- data/Rakefile +0 -14
- data/benchmarks/rule_application.rb +0 -30
- data/benchmarks/setup.rb +0 -13
- data/bin/console +0 -11
- data/docsite/source/index.html.md +0 -54
- data/docsite/source/operations.html.md +0 -62
- data/docsite/source/predicates.html.md +0 -102
- data/examples/basic.rb +0 -16
- data/spec/integration/result_spec.rb +0 -61
- data/spec/integration/rule_spec.rb +0 -55
- data/spec/shared/predicates.rb +0 -59
- data/spec/shared/rule.rb +0 -74
- data/spec/spec_helper.rb +0 -30
- data/spec/support/mutant.rb +0 -11
- data/spec/unit/operations/and_spec.rb +0 -70
- data/spec/unit/operations/attr_spec.rb +0 -29
- data/spec/unit/operations/check_spec.rb +0 -51
- data/spec/unit/operations/each_spec.rb +0 -49
- data/spec/unit/operations/implication_spec.rb +0 -32
- data/spec/unit/operations/key_spec.rb +0 -135
- data/spec/unit/operations/negation_spec.rb +0 -51
- data/spec/unit/operations/or_spec.rb +0 -75
- data/spec/unit/operations/set_spec.rb +0 -43
- data/spec/unit/operations/xor_spec.rb +0 -63
- data/spec/unit/predicates/array_spec.rb +0 -43
- data/spec/unit/predicates/attr_spec.rb +0 -31
- data/spec/unit/predicates/bool_spec.rb +0 -36
- data/spec/unit/predicates/bytesize_spec.rb +0 -48
- data/spec/unit/predicates/case_spec.rb +0 -35
- data/spec/unit/predicates/date_spec.rb +0 -33
- data/spec/unit/predicates/date_time_spec.rb +0 -33
- data/spec/unit/predicates/decimal_spec.rb +0 -34
- data/spec/unit/predicates/empty_spec.rb +0 -40
- data/spec/unit/predicates/eql_spec.rb +0 -23
- data/spec/unit/predicates/even_spec.rb +0 -33
- data/spec/unit/predicates/excluded_from_spec.rb +0 -37
- data/spec/unit/predicates/excludes_spec.rb +0 -58
- data/spec/unit/predicates/false_spec.rb +0 -37
- data/spec/unit/predicates/filled_spec.rb +0 -40
- data/spec/unit/predicates/float_spec.rb +0 -33
- data/spec/unit/predicates/format_spec.rb +0 -31
- data/spec/unit/predicates/gt_spec.rb +0 -42
- data/spec/unit/predicates/gteq_spec.rb +0 -42
- data/spec/unit/predicates/hash_spec.rb +0 -40
- data/spec/unit/predicates/included_in_spec.rb +0 -37
- data/spec/unit/predicates/includes_spec.rb +0 -24
- data/spec/unit/predicates/int_spec.rb +0 -36
- data/spec/unit/predicates/key_spec.rb +0 -31
- data/spec/unit/predicates/lt_spec.rb +0 -42
- data/spec/unit/predicates/lteq_spec.rb +0 -42
- data/spec/unit/predicates/max_bytesize_spec.rb +0 -39
- data/spec/unit/predicates/max_size_spec.rb +0 -51
- data/spec/unit/predicates/min_bytesize_spec.rb +0 -39
- data/spec/unit/predicates/min_size_spec.rb +0 -51
- data/spec/unit/predicates/none_spec.rb +0 -30
- data/spec/unit/predicates/not_eql_spec.rb +0 -23
- data/spec/unit/predicates/number_spec.rb +0 -39
- data/spec/unit/predicates/odd_spec.rb +0 -33
- data/spec/unit/predicates/respond_to_spec.rb +0 -31
- data/spec/unit/predicates/size_spec.rb +0 -57
- data/spec/unit/predicates/str_spec.rb +0 -34
- data/spec/unit/predicates/time_spec.rb +0 -33
- data/spec/unit/predicates/true_spec.rb +0 -37
- data/spec/unit/predicates/type_spec.rb +0 -37
- data/spec/unit/predicates/uuid_v4_spec.rb +0 -29
- data/spec/unit/predicates_spec.rb +0 -25
- data/spec/unit/rule/predicate_spec.rb +0 -55
- data/spec/unit/rule_compiler_spec.rb +0 -129
- data/spec/unit/rule_spec.rb +0 -213
data/bin/console
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
---
|
2
|
-
title: Introduction
|
3
|
-
description: Predicate logic with composable rules
|
4
|
-
layout: gem-single
|
5
|
-
type: gem
|
6
|
-
name: dry-logic
|
7
|
-
sections:
|
8
|
-
- predicates
|
9
|
-
- operations
|
10
|
-
---
|
11
|
-
|
12
|
-
Predicate logic and rule composition used by:
|
13
|
-
|
14
|
-
* [dry-types](https://github.com/dry-rb/dry-types) for constrained types
|
15
|
-
* [dry-validation](https://github.com/dry-rb/dry-validation) for composing validation rules
|
16
|
-
* your project...?
|
17
|
-
|
18
|
-
## Synopsis
|
19
|
-
|
20
|
-
``` ruby
|
21
|
-
require 'dry/logic'
|
22
|
-
require 'dry/logic/predicates'
|
23
|
-
|
24
|
-
include Dry::Logic
|
25
|
-
|
26
|
-
# Rule::Predicate will only apply its predicate to its input, that’s all
|
27
|
-
|
28
|
-
# require input to have the key :user
|
29
|
-
user_present = Rule::Predicate.new(Predicates[:key?]).curry(:user)
|
30
|
-
# curry allows us to prepare predicates with args, without the input
|
31
|
-
|
32
|
-
# require value to be greater than 18
|
33
|
-
min_18 = Rule::Predicate.new(Predicates[:gt?]).curry(18)
|
34
|
-
|
35
|
-
# use the min_18 predicate on the the value of user[:age]
|
36
|
-
has_min_age = Operations::Key.new(min_18, name: [:user, :age])
|
37
|
-
|
38
|
-
user_rule = user_present & has_min_age
|
39
|
-
|
40
|
-
user_rule.(user: { age: 19 }).success?
|
41
|
-
# => true
|
42
|
-
|
43
|
-
user_rule.(user: { age: 18 }).success?
|
44
|
-
# => false
|
45
|
-
|
46
|
-
user_rule.(user: { age: 'seventeen' })
|
47
|
-
# => ArgumentError: comparison of String with 18 failed
|
48
|
-
|
49
|
-
user_rule.(user: { })
|
50
|
-
# => NoMethodError: undefined method `>' for nil:NilClass
|
51
|
-
|
52
|
-
user_rule.({}).success?
|
53
|
-
# => false
|
54
|
-
```
|
@@ -1,62 +0,0 @@
|
|
1
|
-
---
|
2
|
-
title: Operations
|
3
|
-
layout: gem-single
|
4
|
-
name: dry-logic
|
5
|
-
---
|
6
|
-
|
7
|
-
Dry-logic uses operations to interact with the input passed to the different rules.
|
8
|
-
|
9
|
-
``` ruby
|
10
|
-
require 'dry/logic'
|
11
|
-
require 'dry/logic/predicates'
|
12
|
-
|
13
|
-
include Dry::Logic
|
14
|
-
|
15
|
-
user_present = Rule::Predicate.new(Predicates[:key?]).curry(:user)
|
16
|
-
|
17
|
-
min_18 = Rule::Predicate.new(Predicates[:gt?]).curry(18)
|
18
|
-
|
19
|
-
# Here Operations::Key and Rule::Predicate are use to compose and logic based on the value of a given key e.g [:user, :age]
|
20
|
-
has_min_age = Operations::Key.new(min_18, name: [:user, :age])
|
21
|
-
# => #<Dry::Logic::Operations::Key rules=[#<Dry::Logic::Rule::Predicate predicate=#<Method: Module(Dry::Logic::Predicates::Methods)#gt?> options={:args=>[18]}>] options={:name=>[:user, :age], :evaluator=>#<Dry::Logic::Evaluator::Key path=[:user, :age]>, :path=>[:user, :age]}>
|
22
|
-
|
23
|
-
# Thanks to the composable structure of the library we can use multiple Rules and Operations to create custom logic
|
24
|
-
user_rule = user_present & has_min_age
|
25
|
-
|
26
|
-
user_rule.(user: { age: 19 }).success?
|
27
|
-
# => true
|
28
|
-
```
|
29
|
-
|
30
|
-
* Built-in:
|
31
|
-
- `and`
|
32
|
-
- `or`
|
33
|
-
- `key`
|
34
|
-
- `attr`
|
35
|
-
- `binary`
|
36
|
-
- `check`
|
37
|
-
- `each`
|
38
|
-
- `implication`
|
39
|
-
- `negation`
|
40
|
-
- `set`
|
41
|
-
- `xor`
|
42
|
-
|
43
|
-
Another example, lets create the `all?` method from the `Enumerable` module.
|
44
|
-
|
45
|
-
``` ruby
|
46
|
-
require 'dry/logic'
|
47
|
-
require 'dry/logic/predicates'
|
48
|
-
|
49
|
-
include Dry::Logic
|
50
|
-
|
51
|
-
def all?(value)
|
52
|
-
Operations::Each.new(Rule::Predicate.new(Predicates[:gt?]).curry(value))
|
53
|
-
end
|
54
|
-
|
55
|
-
all_6 = all?(6)
|
56
|
-
|
57
|
-
all_6.([6,7,8,9]).success?
|
58
|
-
# => true
|
59
|
-
|
60
|
-
all_6.([1,2,3,4]).success?
|
61
|
-
# => false
|
62
|
-
```
|
@@ -1,102 +0,0 @@
|
|
1
|
-
---
|
2
|
-
title: Predicates
|
3
|
-
layout: gem-single
|
4
|
-
name: dry-logic
|
5
|
-
---
|
6
|
-
|
7
|
-
Dry-logic comes with a lot predicates to compose multiple rules:
|
8
|
-
|
9
|
-
``` ruby
|
10
|
-
require 'dry/logic'
|
11
|
-
require 'dry/logic/predicates'
|
12
|
-
|
13
|
-
include Dry::Logic
|
14
|
-
```
|
15
|
-
|
16
|
-
Now you can access all built-in predicates:
|
17
|
-
|
18
|
-
``` ruby
|
19
|
-
Predicates[:key?]
|
20
|
-
# => #<Method: Module(Dry::Logic::Predicates::Methods)#key?>
|
21
|
-
```
|
22
|
-
|
23
|
-
In the end predicates return true or false.
|
24
|
-
|
25
|
-
```ruby
|
26
|
-
Predicates[:key?].(:name, {name: 'John'})
|
27
|
-
# => true
|
28
|
-
```
|
29
|
-
|
30
|
-
* Built-in:
|
31
|
-
- `type?`
|
32
|
-
- `none?`
|
33
|
-
- `key?`
|
34
|
-
- `attr?`
|
35
|
-
- `empty?`
|
36
|
-
- `filled?`
|
37
|
-
- `bool?`
|
38
|
-
- `date?`
|
39
|
-
- `date_time?`
|
40
|
-
- `time?`
|
41
|
-
- `number?`
|
42
|
-
- `int?`
|
43
|
-
- `float?`
|
44
|
-
- `decimal?`
|
45
|
-
- `str?`
|
46
|
-
- `hash?`
|
47
|
-
- `array?`
|
48
|
-
- `odd?`
|
49
|
-
- `even?`
|
50
|
-
- `lt?`
|
51
|
-
- `gt?`
|
52
|
-
- `lteq?`
|
53
|
-
- `gteq?`
|
54
|
-
- `size?`
|
55
|
-
- `min_size?`
|
56
|
-
- `max_size?`
|
57
|
-
- `bytesize?`
|
58
|
-
- `min_bytesize?`
|
59
|
-
- `max_bytesize?`
|
60
|
-
- `inclusion?`
|
61
|
-
- `exclusion?`
|
62
|
-
- `included_in?`
|
63
|
-
- `excluded_from?`
|
64
|
-
- `includes?`
|
65
|
-
- `excludes?`
|
66
|
-
- `eql?`
|
67
|
-
- `not_eql?`
|
68
|
-
- `is?`
|
69
|
-
- `case?`
|
70
|
-
- `true?`
|
71
|
-
- `false?`
|
72
|
-
- `format?`
|
73
|
-
- `respond_to?`
|
74
|
-
- `predicate`
|
75
|
-
- `uuid_v4?`
|
76
|
-
|
77
|
-
With predicates you can build more composable and complex operations:
|
78
|
-
For example, let's say we want to check that a given input is a hash and has a specify key.
|
79
|
-
|
80
|
-
``` ruby
|
81
|
-
require 'dry/logic'
|
82
|
-
require 'dry/logic/predicates'
|
83
|
-
|
84
|
-
include Dry::Logic
|
85
|
-
|
86
|
-
is_hash = Rule::Predicate.new(Predicates[:type?]).curry(Hash)
|
87
|
-
# => #<Dry::Logic::Rule::Predicate predicate=#<Method: Module(Dry::Logic::Predicates::Methods)#type?> options={:args=>[:hash]}>
|
88
|
-
name_key = Rule::Predicate.new(Predicates[:key?]).curry(:name)
|
89
|
-
# => #<Dry::Logic::Rule::Predicate predicate=#<Method: Module(Dry::Logic::Predicates::Methods)#key?> options={:args=>[:name]}>
|
90
|
-
|
91
|
-
hash_with_key = is_hash & name_key
|
92
|
-
# => #<Dry::Logic::Operations::And rules=[#<Dry::Logic::Rule::Predicate predicate=#<Method: Module(Dry::Logic::Predicates::Methods)#type?> options={:args=>[:hash]}>, #<Dry::Logic::Rule::Predicate predicate=#<Method: Module(Dry::Logic::Predicates::Methods)#key?> options={:args=>[:name]}>] options={}>
|
93
|
-
|
94
|
-
hash_with_key.(name: 'John').success?
|
95
|
-
# => true
|
96
|
-
|
97
|
-
hash_with_key.(not_valid: 'John').success?
|
98
|
-
# => false
|
99
|
-
|
100
|
-
hash_with_key.([1,2]).success?
|
101
|
-
# => false
|
102
|
-
```
|
data/examples/basic.rb
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'dry/logic'
|
4
|
-
require 'dry/logic/predicates'
|
5
|
-
|
6
|
-
include Dry::Logic
|
7
|
-
|
8
|
-
user_present = Rule::Predicate.build(Predicates[:key?]).curry(:user)
|
9
|
-
|
10
|
-
has_min_age = Operations::Key.new(Rule::Predicate.build(Predicates[:gt?]).curry(18), name: [:user, :age])
|
11
|
-
|
12
|
-
user_rule = user_present & has_min_age
|
13
|
-
|
14
|
-
puts user_rule.(user: { age: 19 }).success?
|
15
|
-
|
16
|
-
puts user_rule.(user: { age: 18 }).success?
|
@@ -1,61 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
RSpec.describe Result do
|
4
|
-
include_context 'predicates'
|
5
|
-
|
6
|
-
describe '#to_s' do
|
7
|
-
shared_examples_for 'string representation' do
|
8
|
-
it 'returns string representation' do
|
9
|
-
expect(rule.(input).to_s).to eql(output)
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
context 'with a predicate' do
|
14
|
-
let(:rule) { Rule::Predicate.build(gt?, args: [18]) }
|
15
|
-
let(:input) { 17 }
|
16
|
-
let(:output) { 'gt?(18, 17)' }
|
17
|
-
|
18
|
-
it_behaves_like 'string representation'
|
19
|
-
end
|
20
|
-
|
21
|
-
context 'with AND operation' do
|
22
|
-
let(:rule) { Rule::Predicate.build(array?).and(Rule::Predicate.build(empty?)) }
|
23
|
-
let(:input) { '' }
|
24
|
-
let(:output) { 'array?("") AND empty?("")' }
|
25
|
-
|
26
|
-
it_behaves_like 'string representation'
|
27
|
-
end
|
28
|
-
|
29
|
-
context 'with OR operation' do
|
30
|
-
let(:rule) { Rule::Predicate.build(array?).or(Rule::Predicate.build(empty?)) }
|
31
|
-
let(:input) { 123 }
|
32
|
-
let(:output) { 'array?(123) OR empty?(123)' }
|
33
|
-
|
34
|
-
it_behaves_like 'string representation'
|
35
|
-
end
|
36
|
-
|
37
|
-
context 'with XOR operation' do
|
38
|
-
let(:rule) { Rule::Predicate.build(array?).xor(Rule::Predicate.build(empty?)) }
|
39
|
-
let(:input) { [] }
|
40
|
-
let(:output) { 'array?([]) XOR empty?([])' }
|
41
|
-
|
42
|
-
it_behaves_like 'string representation'
|
43
|
-
end
|
44
|
-
|
45
|
-
context 'with THEN operation' do
|
46
|
-
let(:rule) { Rule::Predicate.build(array?).then(Rule::Predicate.build(empty?)) }
|
47
|
-
let(:input) { [1, 2, 3] }
|
48
|
-
let(:output) { 'empty?([1, 2, 3])' }
|
49
|
-
|
50
|
-
it_behaves_like 'string representation'
|
51
|
-
end
|
52
|
-
|
53
|
-
context 'with NOT operation' do
|
54
|
-
let(:rule) { Operations::Negation.new(Rule::Predicate.build(array?)) }
|
55
|
-
let(:input) { 'foo' }
|
56
|
-
let(:output) { 'not(array?("foo"))' }
|
57
|
-
|
58
|
-
it_behaves_like 'string representation'
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
@@ -1,55 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'dry-logic'
|
4
|
-
|
5
|
-
RSpec.describe 'Rules' do
|
6
|
-
specify 'defining an anonymous rule with an arbitrary predicate' do
|
7
|
-
rule = Dry::Logic.Rule { |value| value.is_a?(Integer) }
|
8
|
-
|
9
|
-
expect(rule.(1)).to be_success
|
10
|
-
expect(rule[1]).to be(true)
|
11
|
-
end
|
12
|
-
|
13
|
-
specify 'defining a conjunction' do
|
14
|
-
rule = Dry::Logic.Rule(&:even?) & Dry::Logic.Rule { |v| v > 4 }
|
15
|
-
|
16
|
-
expect(rule.(3)).to be_failure
|
17
|
-
expect(rule.(4)).to be_failure
|
18
|
-
expect(rule.(5)).to be_failure
|
19
|
-
expect(rule.(6)).to be_success
|
20
|
-
end
|
21
|
-
|
22
|
-
specify 'defining a disjunction' do
|
23
|
-
rule = Dry::Logic.Rule { |v| v < 4 } | Dry::Logic.Rule { |v| v > 6 }
|
24
|
-
|
25
|
-
expect(rule.(5)).to be_failure
|
26
|
-
expect(rule.(3)).to be_success
|
27
|
-
expect(rule.(7)).to be_success
|
28
|
-
end
|
29
|
-
|
30
|
-
specify 'defining an implication' do
|
31
|
-
rule = Dry::Logic.Rule(&:empty?) > Dry::Logic.Rule { |v| v.is_a?(Array) }
|
32
|
-
|
33
|
-
expect(rule.('foo')).to be_success
|
34
|
-
expect(rule.([1, 2])).to be_success
|
35
|
-
expect(rule.([])).to be_success
|
36
|
-
expect(rule.('')).to be_failure
|
37
|
-
end
|
38
|
-
|
39
|
-
specify 'defining an exclusive disjunction' do
|
40
|
-
rule = Dry::Logic.Rule(&:empty?) ^ Dry::Logic.Rule { |v| v.is_a?(Array) }
|
41
|
-
|
42
|
-
expect(rule.('foo')).to be_failure
|
43
|
-
expect(rule.([])).to be_failure
|
44
|
-
expect(rule.([1, 2])).to be_success
|
45
|
-
expect(rule.('')).to be_success
|
46
|
-
end
|
47
|
-
|
48
|
-
specify 'defining a rule with options' do
|
49
|
-
rule = Dry::Logic::Rule(id: :empty?) { |value| value.empty? }
|
50
|
-
|
51
|
-
expect(rule.('foo')).to be_failure
|
52
|
-
expect(rule.('')).to be_success
|
53
|
-
expect(rule.ast('foo')).to eql([:predicate, [:empty?, [[:value, 'foo']]]])
|
54
|
-
end
|
55
|
-
end
|
data/spec/shared/predicates.rb
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'dry/logic/predicates'
|
4
|
-
|
5
|
-
RSpec.shared_examples 'predicates' do
|
6
|
-
let(:nil?) { Dry::Logic::Predicates[:nil?] }
|
7
|
-
|
8
|
-
let(:array?) { Dry::Logic::Predicates[:array?] }
|
9
|
-
|
10
|
-
let(:empty?) { Dry::Logic::Predicates[:empty?] }
|
11
|
-
|
12
|
-
let(:str?) { Dry::Logic::Predicates[:str?] }
|
13
|
-
|
14
|
-
let(:true?) { Dry::Logic::Predicates[:true?] }
|
15
|
-
|
16
|
-
let(:hash?) { Dry::Logic::Predicates[:hash?] }
|
17
|
-
|
18
|
-
let(:int?) { Dry::Logic::Predicates[:int?] }
|
19
|
-
|
20
|
-
let(:filled?) { Dry::Logic::Predicates[:filled?] }
|
21
|
-
|
22
|
-
let(:min_size?) { Dry::Logic::Predicates[:min_size?] }
|
23
|
-
|
24
|
-
let(:lt?) { Dry::Logic::Predicates[:lt?] }
|
25
|
-
|
26
|
-
let(:gt?) { Dry::Logic::Predicates[:gt?] }
|
27
|
-
|
28
|
-
let(:key?) { Dry::Logic::Predicates[:key?] }
|
29
|
-
|
30
|
-
let(:attr?) { Dry::Logic::Predicates[:attr?] }
|
31
|
-
|
32
|
-
let(:eql?) { Dry::Logic::Predicates[:eql?] }
|
33
|
-
|
34
|
-
let(:size?) { Dry::Logic::Predicates[:size?] }
|
35
|
-
|
36
|
-
let(:case?) { Dry::Logic::Predicates[:case?] }
|
37
|
-
|
38
|
-
let(:equal?) { Dry::Logic::Predicates[:equal?] }
|
39
|
-
end
|
40
|
-
|
41
|
-
RSpec.shared_examples 'a passing predicate' do
|
42
|
-
let(:predicate) { Dry::Logic::Predicates[predicate_name] }
|
43
|
-
|
44
|
-
it do
|
45
|
-
arguments_list.each do |args|
|
46
|
-
expect(predicate.call(*args)).to be(true)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
RSpec.shared_examples 'a failing predicate' do
|
52
|
-
let(:predicate) { Dry::Logic::Predicates[predicate_name] }
|
53
|
-
|
54
|
-
it do
|
55
|
-
arguments_list.each do |args|
|
56
|
-
expect(predicate.call(*args)).to be(false)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
data/spec/shared/rule.rb
DELETED
@@ -1,74 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
shared_examples_for Dry::Logic::Rule do
|
4
|
-
let(:arity) { 2 }
|
5
|
-
let(:predicate) { double(:predicate, arity: arity, name: predicate_name) }
|
6
|
-
let(:rule_type) { described_class }
|
7
|
-
let(:predicate_name) { :good? }
|
8
|
-
|
9
|
-
describe '#arity' do
|
10
|
-
it 'returns its predicate arity' do
|
11
|
-
rule = rule_type.build(predicate)
|
12
|
-
|
13
|
-
expect(rule.arity).to be(2)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
describe '#parameters' do
|
18
|
-
it 'returns a list of args with their names' do
|
19
|
-
rule = rule_type.build(-> foo, bar { true }, args: [312])
|
20
|
-
|
21
|
-
expect(rule.parameters).to eql([[:req, :foo], [:req, :bar]])
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
describe '#call' do
|
26
|
-
let(:arity) { 1 }
|
27
|
-
|
28
|
-
it 'returns success for valid input' do
|
29
|
-
rule = rule_type.build(predicate)
|
30
|
-
|
31
|
-
expect(predicate).to receive(:[]).with(2).and_return(true)
|
32
|
-
|
33
|
-
expect(rule.(2)).to be_success
|
34
|
-
end
|
35
|
-
|
36
|
-
it 'returns failure for invalid input' do
|
37
|
-
rule = rule_type.build(predicate)
|
38
|
-
|
39
|
-
expect(predicate).to receive(:[]).with(2).and_return(false)
|
40
|
-
|
41
|
-
expect(rule.(2)).to be_failure
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
describe '#[]' do
|
46
|
-
let(:arity) { 1 }
|
47
|
-
|
48
|
-
it 'delegates to its predicate' do
|
49
|
-
rule = rule_type.build(predicate)
|
50
|
-
|
51
|
-
expect(predicate).to receive(:[]).with(2).and_return(true)
|
52
|
-
expect(rule[2]).to be(true)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
describe '#curry' do
|
57
|
-
it 'returns a curried rule' do
|
58
|
-
rule = rule_type.build(predicate).curry(3)
|
59
|
-
|
60
|
-
expect(predicate).to receive(:[]).with(3, 2).and_return(true)
|
61
|
-
expect(rule.args).to eql([3])
|
62
|
-
|
63
|
-
expect(rule.(2)).to be_success
|
64
|
-
end
|
65
|
-
|
66
|
-
it 'raises argument error when arity does not match' do
|
67
|
-
expect(predicate).to receive(:arity).and_return(2)
|
68
|
-
|
69
|
-
expect { rule_type.build(predicate).curry(3, 2, 1) }.to raise_error(
|
70
|
-
ArgumentError, 'wrong number of arguments (3 for 2)'
|
71
|
-
)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|