dry-logic 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8ed31141ff3e52c81a9afce4397631ce26372a7e
4
- data.tar.gz: ee8d692843523fc91d4e9f6d28a03e4e749362b5
3
+ metadata.gz: 9042bd42bf10c567eb88dc6e830ebface1daf974
4
+ data.tar.gz: dc92016f7c8a14ddd0db49f33d0818130cc9cada
5
5
  SHA512:
6
- metadata.gz: 61463a874fb6281033cba937136a44131df14b59b1fab36532786f47f698eeaa96fbca1cdcc8235ee93b69d66e85da5230bd2c15094720c102024ee01355bc0b
7
- data.tar.gz: 48f375ae23737143a1aea7ba6494f47de0aa86548278f66dedd45333473a177f1a3704e0451777ef1b128669e68006fee952ccf10634f0f928ec28fe5942f738
6
+ metadata.gz: 049784897429ec2b7064da4217cd508d6557bdf4a3c9208e716a608d43c03b9f449a782cef01df03a1786ecb11216f2208ed576eaf1ef8ff93cd92a66ce347af
7
+ data.tar.gz: 64b6dbcd4d3e5b9e06f6b50fb1c1bfd6bd7b856d01b67f2357e46f93a0f716f600bce868b0aec0bd83d9a0e5a8141583aaf18a01a5a119766044f792c93a7467
@@ -1,3 +1,12 @@
1
- # v0.1.0 to-be-released
1
+ # v0.1.1 2016-01-18
2
+
3
+ ### Added
4
+
5
+ * `Rule::Attr` which can be applied to a data object with attr readers (SunnyMagadan)
6
+ * `Rule::Result` which can be applied to a result object (solnic)
7
+
8
+ [Compare v0.1.0...v0.1.1](https://github.com/dryrb/dry-logic/compare/v0.1.0...v0.1.1)
9
+
10
+ # v0.1.0 2016-01-11
2
11
 
3
12
  Code extracted from dry-validation 0.4.1
@@ -23,6 +23,10 @@ module Dry
23
23
  input.key?(name)
24
24
  end
25
25
 
26
+ predicate(:attr?) do |name, input|
27
+ input.respond_to?(name)
28
+ end
29
+
26
30
  predicate(:empty?) do |input|
27
31
  case input
28
32
  when String, Array, Hash then input.empty?
@@ -121,6 +125,14 @@ module Dry
121
125
  left.eql?(right)
122
126
  end
123
127
 
128
+ predicate(:true?) do |value|
129
+ value === true
130
+ end
131
+
132
+ predicate(:false?) do |value|
133
+ value === false
134
+ end
135
+
124
136
  predicate(:format?) do |regex, input|
125
137
  !regex.match(input).nil?
126
138
  end
@@ -42,7 +42,7 @@ module Dry
42
42
  @predicate_id = predicate_id
43
43
  end
44
44
 
45
- def call
45
+ def call(*)
46
46
  Logic.Result(input, success?, rule)
47
47
  end
48
48
 
@@ -56,6 +56,24 @@ module Dry
56
56
  end
57
57
  end
58
58
 
59
+ class Result::LazyValue < Result
60
+ def to_ary
61
+ [:input, [rule.name, input, [rule.to_ary]]]
62
+ end
63
+ alias_method :to_a, :to_ary
64
+
65
+ def input
66
+ success? ? rule.evaluate_input(@input) : @input
67
+ end
68
+ end
69
+
70
+ class Result::Wrapped < Result
71
+ def to_ary
72
+ [:input, [name, nil, [rule.to_ary]]]
73
+ end
74
+ alias_method :to_a, :to_ary
75
+ end
76
+
59
77
  def initialize(input, value, rule)
60
78
  @input = input
61
79
  @value = value
@@ -63,7 +81,7 @@ module Dry
63
81
  @name = rule.name
64
82
  end
65
83
 
66
- def call
84
+ def call(*)
67
85
  self
68
86
  end
69
87
 
@@ -81,11 +81,13 @@ module Dry
81
81
  end
82
82
 
83
83
  require 'dry/logic/rule/key'
84
+ require 'dry/logic/rule/attr'
84
85
  require 'dry/logic/rule/value'
85
86
  require 'dry/logic/rule/each'
86
87
  require 'dry/logic/rule/set'
87
88
  require 'dry/logic/rule/composite'
88
89
  require 'dry/logic/rule/check'
90
+ require 'dry/logic/rule/result'
89
91
  require 'dry/logic/rule/group'
90
92
 
91
93
  require 'dry/logic/result'
@@ -0,0 +1,21 @@
1
+ module Dry
2
+ module Logic
3
+ class Rule::Attr < Rule
4
+ def self.new(name, predicate)
5
+ super(name, predicate.curry(name))
6
+ end
7
+
8
+ def type
9
+ :attr
10
+ end
11
+
12
+ def evaluate_input(input)
13
+ input.public_send(name)
14
+ end
15
+
16
+ def call(input)
17
+ Logic::Result::LazyValue.new(input, predicate.(input), self)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -3,8 +3,8 @@ module Dry
3
3
  class Rule::Check < Rule
4
4
  alias_method :result, :predicate
5
5
 
6
- def call(*)
7
- Logic.Result(nil, result.call, self)
6
+ def call(*args)
7
+ Logic.Result(nil, result.(*args), self)
8
8
  end
9
9
 
10
10
  def type
@@ -0,0 +1,16 @@
1
+ module Dry
2
+ module Logic
3
+ class Rule::Result < Rule
4
+ def call(input)
5
+ result = input[name]
6
+ return result unless result.success?
7
+ result_input = result.input
8
+ Result::Wrapped.new(input, predicate.(result_input), self)
9
+ end
10
+
11
+ def type
12
+ :res
13
+ end
14
+ end
15
+ end
16
+ end
@@ -23,6 +23,11 @@ module Dry
23
23
  Rule::Check.new(name, visit(predicate))
24
24
  end
25
25
 
26
+ def visit_res(node)
27
+ name, predicate = node
28
+ Rule::Result.new(name, visit(predicate))
29
+ end
30
+
26
31
  def visit_not(node)
27
32
  visit(node).negation
28
33
  end
@@ -32,6 +37,11 @@ module Dry
32
37
  Rule::Key.new(name, visit(predicate))
33
38
  end
34
39
 
40
+ def visit_attr(node)
41
+ name, predicate = node
42
+ Rule::Attr.new(name, visit(predicate))
43
+ end
44
+
35
45
  def visit_val(node)
36
46
  name, predicate = node
37
47
  Rule::Value.new(name, visit(predicate))
@@ -1,5 +1,5 @@
1
1
  module Dry
2
2
  module Logic
3
- VERSION = '0.1.0'.freeze
3
+ VERSION = '0.1.1'.freeze
4
4
  end
5
5
  end
@@ -17,6 +17,8 @@ RSpec.shared_examples 'predicates' do
17
17
 
18
18
  let(:key?) { Dry::Logic::Predicates[:key?] }
19
19
 
20
+ let(:attr?) { Dry::Logic::Predicates[:attr?] }
21
+
20
22
  let(:eql?) { Dry::Logic::Predicates[:eql?] }
21
23
  end
22
24
 
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  begin
4
2
  require 'byebug'
5
3
  rescue LoadError; end
@@ -0,0 +1,29 @@
1
+ require 'dry/logic/predicates'
2
+
3
+ RSpec.describe Dry::Logic::Predicates do
4
+ describe '#attr?' do
5
+ let(:predicate_name) { :attr? }
6
+
7
+ context 'when value responds to the attr name' do
8
+ let(:arguments_list) do
9
+ [
10
+ [:name, Struct.new(:name).new('John')],
11
+ [:age, Struct.new(:age).new(18)]
12
+ ]
13
+ end
14
+
15
+ it_behaves_like 'a passing predicate'
16
+ end
17
+
18
+ context 'with value does not respond to the attr name' do
19
+ let(:arguments_list) do
20
+ [
21
+ [:name, Struct.new(:age).new(18)],
22
+ [:age, Struct.new(:name).new('Jill')]
23
+ ]
24
+ end
25
+
26
+ it_behaves_like 'a failing predicate'
27
+ end
28
+ end
29
+ end
@@ -12,7 +12,7 @@ RSpec.describe Dry::Logic::Predicates do
12
12
  it_behaves_like 'a passing predicate'
13
13
  end
14
14
 
15
- context 'with value is not an integer' do
15
+ context 'when value is not a bool' do
16
16
  let(:arguments_list) do
17
17
  [
18
18
  [''],
@@ -0,0 +1,35 @@
1
+ require 'dry/logic/predicates'
2
+
3
+ RSpec.describe Dry::Logic::Predicates do
4
+ describe '#false?' do
5
+ let(:predicate_name) { :false? }
6
+
7
+ context 'when value is a date' do
8
+ let(:arguments_list) do
9
+ [[false]]
10
+ end
11
+
12
+ it_behaves_like 'a passing predicate'
13
+ end
14
+
15
+ context 'when value is not false' do
16
+ let(:arguments_list) do
17
+ [
18
+ [true],
19
+ [''],
20
+ [[]],
21
+ [{}],
22
+ [nil],
23
+ [:symbol],
24
+ [String],
25
+ [1],
26
+ [0],
27
+ ['true'],
28
+ ['false']
29
+ ]
30
+ end
31
+
32
+ it_behaves_like 'a failing predicate'
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,35 @@
1
+ require 'dry/logic/predicates'
2
+
3
+ RSpec.describe Dry::Logic::Predicates do
4
+ describe '#true?' do
5
+ let(:predicate_name) { :true? }
6
+
7
+ context 'when value is a date' do
8
+ let(:arguments_list) do
9
+ [[true]]
10
+ end
11
+
12
+ it_behaves_like 'a passing predicate'
13
+ end
14
+
15
+ context 'with value is not true' do
16
+ let(:arguments_list) do
17
+ [
18
+ [false],
19
+ [''],
20
+ [[]],
21
+ [{}],
22
+ [nil],
23
+ [:symbol],
24
+ [String],
25
+ [1],
26
+ [0],
27
+ ['true'],
28
+ ['false']
29
+ ]
30
+ end
31
+
32
+ it_behaves_like 'a failing predicate'
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,29 @@
1
+ require 'dry/logic/rule'
2
+
3
+ RSpec.describe Dry::Logic::Rule::Attr do
4
+ include_context 'predicates'
5
+
6
+ let(:model) { Struct.new(:name) }
7
+
8
+ subject(:rule) { described_class.new(:name, attr?) }
9
+
10
+ describe '#call' do
11
+ it 'applies predicate to the value' do
12
+ expect(rule.(model.new(name: 'Jane'))).to be_success
13
+ expect(rule.(nil)).to be_failure
14
+ end
15
+ end
16
+
17
+ describe '#and' do
18
+ let(:other) { Dry::Logic::Rule::Value.new(:name, str?) }
19
+
20
+ it 'returns conjunction rule where value is passed to the right' do
21
+ present_and_string = rule.and(other)
22
+
23
+ expect(present_and_string.(model.new('Jane'))).to be_success
24
+
25
+ expect(present_and_string.(nil)).to be_failure
26
+ expect(present_and_string.(model.new(1))).to be_failure
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,33 @@
1
+ require 'dry/logic/rule/result'
2
+
3
+ RSpec.describe Dry::Logic::Rule::Result do
4
+ subject(:rule) { Dry::Logic::Rule::Result.new(:name, min_size?.curry(4)) }
5
+
6
+ include_context 'predicates'
7
+
8
+ let(:is_str) { Dry::Logic::Rule::Value.new(:name, str?) }
9
+ let(:is_jane) { Dry::Logic::Rule::Result.new(:name, eql?.curry('jane')) }
10
+
11
+ describe '#call' do
12
+ it 'returns result of a predicate' do
13
+ expect(rule.(name: is_str.('jane'))).to be_success
14
+ expect(rule.(name: is_str.('jan'))).to be_failure
15
+ expect(rule.(name: is_str.(nil))).to be_failure
16
+ end
17
+
18
+ it 'evaluates input for the ast' do
19
+ expect(rule.(name: is_str.('jane')).to_ary).to eql([
20
+ :input, [
21
+ :name, nil, [[:res, [:name, [:predicate, [:min_size?, [4]]]]]]
22
+ ]
23
+ ])
24
+ end
25
+ end
26
+
27
+ describe '#and' do
28
+ it 'returns result of a conjunction' do
29
+ expect(rule.and(is_jane).(name: is_str.('jane'))).to be_success
30
+ expect(rule.and(is_jane).(name: is_str.('john'))).to be_failure
31
+ end
32
+ end
33
+ end
@@ -5,6 +5,7 @@ RSpec.describe Dry::Logic::RuleCompiler, '#call' do
5
5
 
6
6
  let(:predicates) {
7
7
  { key?: predicate,
8
+ attr?: predicate,
8
9
  filled?: predicate,
9
10
  email: val_rule.('email').curry(:filled?) }
10
11
  }
@@ -13,8 +14,10 @@ RSpec.describe Dry::Logic::RuleCompiler, '#call' do
13
14
 
14
15
  let(:key_rule) { Rule::Key.new(:email, predicate) }
15
16
  let(:not_key_rule) { Rule::Key.new(:email, predicate).negation }
17
+ let(:attr_rule) { Rule::Attr.new(:email, predicate) }
16
18
  let(:val_rule) { Rule::Value.new(:email, predicate) }
17
19
  let(:check_rule) { Rule::Check.new(:email, predicates[:email]) }
20
+ let(:res_rule) { Rule::Result.new(:email, predicates[:email]) }
18
21
  let(:and_rule) { key_rule & val_rule }
19
22
  let(:or_rule) { key_rule | val_rule }
20
23
  let(:xor_rule) { key_rule ^ val_rule }
@@ -37,6 +40,21 @@ RSpec.describe Dry::Logic::RuleCompiler, '#call' do
37
40
  expect(rules).to eql([check_rule])
38
41
  end
39
42
 
43
+ it 'compiles result rules' do
44
+ ast = [[:res, [:email, [:predicate, [:email, [:filled?]]]]]]
45
+
46
+ rules = compiler.(ast)
47
+
48
+ expect(rules).to eql([res_rule])
49
+ end
50
+
51
+ it 'compiles attr rules' do
52
+ ast = [[:attr, [:email, [:predicate, [:attr?, predicate]]]]]
53
+
54
+ rules = compiler.(ast)
55
+
56
+ expect(rules).to eql([attr_rule])
57
+ end
40
58
 
41
59
  it 'compiles negated rules' do
42
60
  ast = [[:not, [:key, [:email, [:predicate, [:key?, predicate]]]]]]
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dry-logic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Solnica
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-11 00:00:00.000000000 Z
11
+ date: 2016-01-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-container
@@ -112,11 +112,13 @@ files:
112
112
  - lib/dry/logic/predicates.rb
113
113
  - lib/dry/logic/result.rb
114
114
  - lib/dry/logic/rule.rb
115
+ - lib/dry/logic/rule/attr.rb
115
116
  - lib/dry/logic/rule/check.rb
116
117
  - lib/dry/logic/rule/composite.rb
117
118
  - lib/dry/logic/rule/each.rb
118
119
  - lib/dry/logic/rule/group.rb
119
120
  - lib/dry/logic/rule/key.rb
121
+ - lib/dry/logic/rule/result.rb
120
122
  - lib/dry/logic/rule/set.rb
121
123
  - lib/dry/logic/rule/value.rb
122
124
  - lib/dry/logic/rule_compiler.rb
@@ -125,6 +127,7 @@ files:
125
127
  - spec/shared/predicates.rb
126
128
  - spec/spec_helper.rb
127
129
  - spec/unit/predicate_spec.rb
130
+ - spec/unit/predicates/attr_spec.rb
128
131
  - spec/unit/predicates/bool_spec.rb
129
132
  - spec/unit/predicates/date_spec.rb
130
133
  - spec/unit/predicates/date_time_spec.rb
@@ -132,6 +135,7 @@ files:
132
135
  - spec/unit/predicates/empty_spec.rb
133
136
  - spec/unit/predicates/eql_spec.rb
134
137
  - spec/unit/predicates/exclusion_spec.rb
138
+ - spec/unit/predicates/false_spec.rb
135
139
  - spec/unit/predicates/filled_spec.rb
136
140
  - spec/unit/predicates/float_spec.rb
137
141
  - spec/unit/predicates/format_spec.rb
@@ -148,6 +152,8 @@ files:
148
152
  - spec/unit/predicates/size_spec.rb
149
153
  - spec/unit/predicates/str_spec.rb
150
154
  - spec/unit/predicates/time_spec.rb
155
+ - spec/unit/predicates/true_spec.rb
156
+ - spec/unit/rule/attr_spec.rb
151
157
  - spec/unit/rule/check_spec.rb
152
158
  - spec/unit/rule/conjunction_spec.rb
153
159
  - spec/unit/rule/disjunction_spec.rb
@@ -155,6 +161,7 @@ files:
155
161
  - spec/unit/rule/group_spec.rb
156
162
  - spec/unit/rule/implication_spec.rb
157
163
  - spec/unit/rule/key_spec.rb
164
+ - spec/unit/rule/result_spec.rb
158
165
  - spec/unit/rule/set_spec.rb
159
166
  - spec/unit/rule/value_spec.rb
160
167
  - spec/unit/rule_compiler_spec.rb
@@ -186,6 +193,7 @@ test_files:
186
193
  - spec/shared/predicates.rb
187
194
  - spec/spec_helper.rb
188
195
  - spec/unit/predicate_spec.rb
196
+ - spec/unit/predicates/attr_spec.rb
189
197
  - spec/unit/predicates/bool_spec.rb
190
198
  - spec/unit/predicates/date_spec.rb
191
199
  - spec/unit/predicates/date_time_spec.rb
@@ -193,6 +201,7 @@ test_files:
193
201
  - spec/unit/predicates/empty_spec.rb
194
202
  - spec/unit/predicates/eql_spec.rb
195
203
  - spec/unit/predicates/exclusion_spec.rb
204
+ - spec/unit/predicates/false_spec.rb
196
205
  - spec/unit/predicates/filled_spec.rb
197
206
  - spec/unit/predicates/float_spec.rb
198
207
  - spec/unit/predicates/format_spec.rb
@@ -209,6 +218,8 @@ test_files:
209
218
  - spec/unit/predicates/size_spec.rb
210
219
  - spec/unit/predicates/str_spec.rb
211
220
  - spec/unit/predicates/time_spec.rb
221
+ - spec/unit/predicates/true_spec.rb
222
+ - spec/unit/rule/attr_spec.rb
212
223
  - spec/unit/rule/check_spec.rb
213
224
  - spec/unit/rule/conjunction_spec.rb
214
225
  - spec/unit/rule/disjunction_spec.rb
@@ -216,6 +227,7 @@ test_files:
216
227
  - spec/unit/rule/group_spec.rb
217
228
  - spec/unit/rule/implication_spec.rb
218
229
  - spec/unit/rule/key_spec.rb
230
+ - spec/unit/rule/result_spec.rb
219
231
  - spec/unit/rule/set_spec.rb
220
232
  - spec/unit/rule/value_spec.rb
221
233
  - spec/unit/rule_compiler_spec.rb