dry-logic 0.5.0 → 1.5.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 +222 -17
- data/LICENSE +1 -1
- data/README.md +11 -20
- data/dry-logic.gemspec +36 -20
- data/lib/dry/logic/appliable.rb +2 -0
- data/lib/dry/logic/builder.rb +88 -0
- data/lib/dry/logic/evaluator.rb +1 -1
- data/lib/dry/logic/operations/abstract.rb +4 -6
- data/lib/dry/logic/operations/and.rb +12 -3
- data/lib/dry/logic/operations/attr.rb +1 -1
- data/lib/dry/logic/operations/binary.rb +4 -3
- data/lib/dry/logic/operations/check.rb +3 -5
- data/lib/dry/logic/operations/each.rb +1 -2
- data/lib/dry/logic/operations/implication.rb +1 -2
- data/lib/dry/logic/operations/key.rb +3 -5
- data/lib/dry/logic/operations/negation.rb +1 -2
- data/lib/dry/logic/operations/or.rb +1 -2
- data/lib/dry/logic/operations/set.rb +3 -4
- data/lib/dry/logic/operations/unary.rb +1 -1
- data/lib/dry/logic/operations/xor.rb +1 -2
- data/lib/dry/logic/operators.rb +6 -4
- data/lib/dry/logic/predicates.rb +110 -28
- data/lib/dry/logic/result.rb +2 -4
- data/lib/dry/logic/rule/interface.rb +143 -0
- data/lib/dry/logic/rule/predicate.rb +23 -17
- data/lib/dry/logic/rule.rb +31 -31
- data/lib/dry/logic/rule_compiler.rb +2 -7
- data/lib/dry/logic/version.rb +3 -1
- data/lib/dry/logic.rb +21 -5
- data/lib/dry-logic.rb +3 -1
- metadata +27 -143
- data/.codeclimate.yml +0 -23
- data/.gitignore +0 -7
- data/.rspec +0 -3
- data/.rubocop.yml +0 -16
- data/.rubocop_todo.yml +0 -7
- data/.travis.yml +0 -30
- data/CONTRIBUTING.md +0 -29
- data/Gemfile +0 -17
- data/Rakefile +0 -12
- data/bin/console +0 -10
- data/examples/basic.rb +0 -14
- data/lib/dry/logic/operations.rb +0 -13
- data/spec/integration/result_spec.rb +0 -59
- data/spec/integration/rule_spec.rb +0 -53
- data/spec/shared/predicates.rb +0 -57
- data/spec/shared/rule.rb +0 -67
- data/spec/spec_helper.rb +0 -34
- data/spec/support/mutant.rb +0 -9
- data/spec/unit/operations/and_spec.rb +0 -64
- data/spec/unit/operations/attr_spec.rb +0 -27
- data/spec/unit/operations/check_spec.rb +0 -49
- data/spec/unit/operations/each_spec.rb +0 -47
- data/spec/unit/operations/implication_spec.rb +0 -30
- data/spec/unit/operations/key_spec.rb +0 -133
- data/spec/unit/operations/negation_spec.rb +0 -49
- data/spec/unit/operations/or_spec.rb +0 -73
- data/spec/unit/operations/set_spec.rb +0 -41
- data/spec/unit/operations/xor_spec.rb +0 -61
- data/spec/unit/predicates/array_spec.rb +0 -41
- data/spec/unit/predicates/attr_spec.rb +0 -29
- data/spec/unit/predicates/bool_spec.rb +0 -34
- data/spec/unit/predicates/case_spec.rb +0 -33
- data/spec/unit/predicates/date_spec.rb +0 -31
- data/spec/unit/predicates/date_time_spec.rb +0 -31
- data/spec/unit/predicates/decimal_spec.rb +0 -32
- data/spec/unit/predicates/empty_spec.rb +0 -38
- data/spec/unit/predicates/eql_spec.rb +0 -21
- data/spec/unit/predicates/even_spec.rb +0 -31
- data/spec/unit/predicates/excluded_from_spec.rb +0 -35
- data/spec/unit/predicates/excludes_spec.rb +0 -56
- data/spec/unit/predicates/false_spec.rb +0 -35
- data/spec/unit/predicates/filled_spec.rb +0 -38
- data/spec/unit/predicates/float_spec.rb +0 -31
- data/spec/unit/predicates/format_spec.rb +0 -21
- data/spec/unit/predicates/gt_spec.rb +0 -40
- data/spec/unit/predicates/gteq_spec.rb +0 -40
- data/spec/unit/predicates/included_in_spec.rb +0 -35
- data/spec/unit/predicates/includes_spec.rb +0 -24
- data/spec/unit/predicates/int_spec.rb +0 -34
- data/spec/unit/predicates/key_spec.rb +0 -29
- data/spec/unit/predicates/lt_spec.rb +0 -40
- data/spec/unit/predicates/lteq_spec.rb +0 -40
- data/spec/unit/predicates/max_size_spec.rb +0 -49
- data/spec/unit/predicates/min_size_spec.rb +0 -49
- data/spec/unit/predicates/none_spec.rb +0 -28
- data/spec/unit/predicates/not_eql_spec.rb +0 -21
- data/spec/unit/predicates/number_spec.rb +0 -37
- data/spec/unit/predicates/odd_spec.rb +0 -31
- data/spec/unit/predicates/size_spec.rb +0 -55
- data/spec/unit/predicates/str_spec.rb +0 -32
- data/spec/unit/predicates/time_spec.rb +0 -31
- data/spec/unit/predicates/true_spec.rb +0 -35
- data/spec/unit/predicates/type_spec.rb +0 -35
- data/spec/unit/predicates_spec.rb +0 -23
- data/spec/unit/rule/predicate_spec.rb +0 -53
- data/spec/unit/rule_compiler_spec.rb +0 -127
- data/spec/unit/rule_spec.rb +0 -141
@@ -1,127 +0,0 @@
|
|
1
|
-
require 'dry/logic/rule_compiler'
|
2
|
-
|
3
|
-
RSpec.describe Dry::Logic::RuleCompiler, '#call' do
|
4
|
-
subject(:compiler) { RuleCompiler.new(predicates) }
|
5
|
-
|
6
|
-
let(:predicates) {
|
7
|
-
{ key?: predicate,
|
8
|
-
attr?: predicate,
|
9
|
-
filled?: predicate,
|
10
|
-
gt?: predicate,
|
11
|
-
one: predicate }
|
12
|
-
}
|
13
|
-
|
14
|
-
let(:predicate) { double(:predicate, name: :test?, arity: 2).as_null_object }
|
15
|
-
|
16
|
-
let(:rule) { Rule::Predicate.new(predicate) }
|
17
|
-
let(:key_op) { Operations::Key.new(rule, name: :email) }
|
18
|
-
let(:attr_op) { Operations::Attr.new(rule, name: :email) }
|
19
|
-
let(:check_op) { Operations::Check.new(rule, keys: [:email]) }
|
20
|
-
let(:not_key_op) { Operations::Negation.new(key_op) }
|
21
|
-
let(:and_op) { key_op.curry(:email) & rule }
|
22
|
-
let(:or_op) { key_op.curry(:email) | rule }
|
23
|
-
let(:xor_op) { key_op.curry(:email) ^ rule }
|
24
|
-
let(:set_op) { Operations::Set.new(rule) }
|
25
|
-
let(:each_op) { Operations::Each.new(rule) }
|
26
|
-
|
27
|
-
it 'compiles key rules' do
|
28
|
-
ast = [[:key, [:email, [:predicate, [:filled?, [[:input, Undefined]]]]]]]
|
29
|
-
|
30
|
-
rules = compiler.(ast)
|
31
|
-
|
32
|
-
expect(rules).to eql([key_op])
|
33
|
-
end
|
34
|
-
|
35
|
-
it 'compiles attr rules' do
|
36
|
-
ast = [[:attr, [:email, [:predicate, [:filled?, [[:input, Undefined]]]]]]]
|
37
|
-
|
38
|
-
rules = compiler.(ast)
|
39
|
-
|
40
|
-
expect(rules).to eql([attr_op])
|
41
|
-
end
|
42
|
-
|
43
|
-
it 'compiles check rules' do
|
44
|
-
ast = [[:check, [[:email], [:predicate, [:filled?, [[:input, Undefined]]]]]]]
|
45
|
-
|
46
|
-
rules = compiler.(ast)
|
47
|
-
|
48
|
-
expect(rules).to eql([check_op])
|
49
|
-
end
|
50
|
-
|
51
|
-
it 'compiles attr rules' do
|
52
|
-
ast = [[:attr, [:email, [:predicate, [:filled?, [[:input, Undefined]]]]]]]
|
53
|
-
|
54
|
-
rules = compiler.(ast)
|
55
|
-
|
56
|
-
expect(rules).to eql([attr_op])
|
57
|
-
end
|
58
|
-
|
59
|
-
it 'compiles negated rules' do
|
60
|
-
ast = [[:not, [:key, [:email, [:predicate, [:filled?, [[:input, Undefined]]]]]]]]
|
61
|
-
|
62
|
-
rules = compiler.(ast)
|
63
|
-
|
64
|
-
expect(rules).to eql([not_key_op])
|
65
|
-
end
|
66
|
-
|
67
|
-
it 'compiles and rules' do
|
68
|
-
ast = [
|
69
|
-
[
|
70
|
-
:and, [
|
71
|
-
[:key, [:email, [:predicate, [:key?, [[:name, :email], [:input, Undefined]]]]]],
|
72
|
-
[:predicate, [:filled?, [[:input, Undefined]]]]
|
73
|
-
]
|
74
|
-
]
|
75
|
-
]
|
76
|
-
|
77
|
-
rules = compiler.(ast)
|
78
|
-
|
79
|
-
expect(rules).to eql([and_op])
|
80
|
-
end
|
81
|
-
|
82
|
-
it 'compiles or rules' do
|
83
|
-
ast = [
|
84
|
-
[
|
85
|
-
:or, [
|
86
|
-
[:key, [:email, [:predicate, [:key?, [[:name, :email], [:input, Undefined]]]]]],
|
87
|
-
[:predicate, [:filled?, [[:input, Undefined]]]]
|
88
|
-
]
|
89
|
-
]
|
90
|
-
]
|
91
|
-
|
92
|
-
rules = compiler.(ast)
|
93
|
-
|
94
|
-
expect(rules).to eql([or_op])
|
95
|
-
end
|
96
|
-
|
97
|
-
it 'compiles exclusive or rules' do
|
98
|
-
ast = [
|
99
|
-
[
|
100
|
-
:xor, [
|
101
|
-
[:key, [:email, [:predicate, [:key?, [[:name, :email], [:input, Undefined]]]]]],
|
102
|
-
[:predicate, [:filled?, [[:input, Undefined]]]]
|
103
|
-
]
|
104
|
-
]
|
105
|
-
]
|
106
|
-
|
107
|
-
rules = compiler.(ast)
|
108
|
-
|
109
|
-
expect(rules).to eql([xor_op])
|
110
|
-
end
|
111
|
-
|
112
|
-
it 'compiles set rules' do
|
113
|
-
ast = [[:set, [[:predicate, [:filled?, [[:input, nil]]]]]]]
|
114
|
-
|
115
|
-
rules = compiler.(ast)
|
116
|
-
|
117
|
-
expect(rules).to eql([set_op])
|
118
|
-
end
|
119
|
-
|
120
|
-
it 'compiles each rules' do
|
121
|
-
ast = [[:each, [:predicate, [:filled?, [[:input, nil]]]]]]
|
122
|
-
|
123
|
-
rules = compiler.(ast)
|
124
|
-
|
125
|
-
expect(rules).to eql([each_op])
|
126
|
-
end
|
127
|
-
end
|
data/spec/unit/rule_spec.rb
DELETED
@@ -1,141 +0,0 @@
|
|
1
|
-
RSpec.describe Dry::Logic::Rule do
|
2
|
-
subject(:rule) { Rule.new(predicate, options) }
|
3
|
-
|
4
|
-
let(:predicate) { -> { true } }
|
5
|
-
let(:options) { {} }
|
6
|
-
|
7
|
-
let(:schema) do
|
8
|
-
Class.new(BasicObject) do
|
9
|
-
define_method(:class, Kernel.instance_method(:class))
|
10
|
-
|
11
|
-
def method_missing(m, *)
|
12
|
-
if m.to_s.end_with?('?')
|
13
|
-
self.class.new
|
14
|
-
else
|
15
|
-
super
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def to_proc
|
20
|
-
-> value { value }
|
21
|
-
end
|
22
|
-
|
23
|
-
def arity
|
24
|
-
1
|
25
|
-
end
|
26
|
-
|
27
|
-
def parameters
|
28
|
-
[[:req, :value]]
|
29
|
-
end
|
30
|
-
end.new
|
31
|
-
end
|
32
|
-
|
33
|
-
it_behaves_like Dry::Logic::Rule
|
34
|
-
|
35
|
-
describe '.new' do
|
36
|
-
it 'accepts an :id' do
|
37
|
-
expect(Rule.new(predicate, id: :check_num).id).to be(:check_num)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
describe 'with a function returning truthy value' do
|
42
|
-
it 'is successful for valid input' do
|
43
|
-
expect(Rule.new(-> val { val }).('true')).to be_success
|
44
|
-
end
|
45
|
-
|
46
|
-
it 'is not successful for invalid input' do
|
47
|
-
expect(Rule.new(-> val { val }).(nil)).to be_failure
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
describe '#ast' do
|
52
|
-
it 'returns predicate node with :id' do
|
53
|
-
expect(Rule.new(-> value { true }).with(id: :email?).ast('oops')).to eql(
|
54
|
-
[:predicate, [:email?, [[:value, 'oops']]]]
|
55
|
-
)
|
56
|
-
end
|
57
|
-
|
58
|
-
it 'returns predicate node with undefined args' do
|
59
|
-
expect(Rule.new(-> value { true }).with(id: :email?).ast).to eql(
|
60
|
-
[:predicate, [:email?, [[:value, Undefined]]]]
|
61
|
-
)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
describe '#type' do
|
66
|
-
it 'returns rule type' do
|
67
|
-
expect(rule.type).to be(:rule)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
describe '#bind' do
|
72
|
-
let(:bound) { rule.with(id: :bound).bind(object) }
|
73
|
-
|
74
|
-
context 'with an unbound method' do
|
75
|
-
let(:predicate) { klass.instance_method(:test?) }
|
76
|
-
let(:klass) { Class.new { def test?; true; end } }
|
77
|
-
let(:object) { klass.new }
|
78
|
-
|
79
|
-
it 'returns a new rule with its predicate bound to a specific object' do
|
80
|
-
expect(bound.()).to be_success
|
81
|
-
end
|
82
|
-
|
83
|
-
it 'carries id' do
|
84
|
-
expect(bound.id).to be(:bound)
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
context 'with an arbitrary block' do
|
89
|
-
let(:predicate) { -> value { value == expected } }
|
90
|
-
let(:object) { Class.new { def expected; 'test'; end }.new }
|
91
|
-
|
92
|
-
it 'returns a new with its predicate executed in the context of the provided object' do
|
93
|
-
expect(bound.('test')).to be_success
|
94
|
-
expect(bound.('oops')).to be_failure
|
95
|
-
end
|
96
|
-
|
97
|
-
it 'carries id' do
|
98
|
-
expect(bound.id).to be(:bound)
|
99
|
-
end
|
100
|
-
|
101
|
-
it 'stores arity' do
|
102
|
-
expect(bound.options[:arity]).to be(rule.arity)
|
103
|
-
end
|
104
|
-
|
105
|
-
it 'stores parameters' do
|
106
|
-
expect(bound.options[:parameters]).to eql(rule.parameters)
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
context 'with a schema instance' do
|
111
|
-
let(:object) { schema }
|
112
|
-
let(:predicate) { schema }
|
113
|
-
|
114
|
-
it 'returns a new with its predicate executed in the context of the provided object' do
|
115
|
-
expect(bound.(true)).to be_success
|
116
|
-
expect(bound.(false)).to be_failure
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
describe '#eval_args' do
|
122
|
-
context 'with an unbound method' do
|
123
|
-
let(:options) { { args: [1, klass.instance_method(:num), :foo] } }
|
124
|
-
let(:klass) { Class.new { def num; 7; end } }
|
125
|
-
let(:object) { klass.new }
|
126
|
-
|
127
|
-
it 'evaluates args in the context of the provided object' do
|
128
|
-
expect(rule.eval_args(object).args).to eql([1, 7, :foo])
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
context 'with a schema instance' do
|
133
|
-
let(:options) { { args: [1, schema, :foo] } }
|
134
|
-
let(:object) { Object.new }
|
135
|
-
|
136
|
-
it 'returns a new with its predicate executed in the context of the provided object' do
|
137
|
-
expect(rule.eval_args(object).args).to eql([1, schema, :foo])
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
141
|
-
end
|