dry-logic 1.0.5 → 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +76 -26
  3. data/LICENSE +1 -1
  4. data/README.md +12 -14
  5. data/dry-logic.gemspec +27 -20
  6. data/lib/dry/logic/predicates.rb +1 -1
  7. data/lib/dry/logic/rule/interface.rb +1 -1
  8. data/lib/dry/logic/version.rb +1 -1
  9. metadata +9 -150
  10. data/.codeclimate.yml +0 -12
  11. data/.github/ISSUE_TEMPLATE/----please-don-t-ask-for-support-via-issues.md +0 -10
  12. data/.github/ISSUE_TEMPLATE/---bug-report.md +0 -34
  13. data/.github/ISSUE_TEMPLATE/---feature-request.md +0 -18
  14. data/.github/workflows/ci.yml +0 -70
  15. data/.github/workflows/docsite.yml +0 -34
  16. data/.github/workflows/sync_configs.yml +0 -34
  17. data/.gitignore +0 -9
  18. data/.rspec +0 -4
  19. data/.rubocop.yml +0 -89
  20. data/CODE_OF_CONDUCT.md +0 -13
  21. data/CONTRIBUTING.md +0 -29
  22. data/Gemfile +0 -16
  23. data/Rakefile +0 -14
  24. data/benchmarks/rule_application.rb +0 -30
  25. data/benchmarks/setup.rb +0 -13
  26. data/bin/console +0 -11
  27. data/docsite/source/index.html.md +0 -54
  28. data/docsite/source/operations.html.md +0 -62
  29. data/docsite/source/predicates.html.md +0 -102
  30. data/examples/basic.rb +0 -16
  31. data/spec/integration/result_spec.rb +0 -61
  32. data/spec/integration/rule_spec.rb +0 -55
  33. data/spec/shared/predicates.rb +0 -59
  34. data/spec/shared/rule.rb +0 -74
  35. data/spec/spec_helper.rb +0 -30
  36. data/spec/support/mutant.rb +0 -11
  37. data/spec/unit/operations/and_spec.rb +0 -70
  38. data/spec/unit/operations/attr_spec.rb +0 -29
  39. data/spec/unit/operations/check_spec.rb +0 -51
  40. data/spec/unit/operations/each_spec.rb +0 -49
  41. data/spec/unit/operations/implication_spec.rb +0 -32
  42. data/spec/unit/operations/key_spec.rb +0 -135
  43. data/spec/unit/operations/negation_spec.rb +0 -51
  44. data/spec/unit/operations/or_spec.rb +0 -75
  45. data/spec/unit/operations/set_spec.rb +0 -43
  46. data/spec/unit/operations/xor_spec.rb +0 -63
  47. data/spec/unit/predicates/array_spec.rb +0 -43
  48. data/spec/unit/predicates/attr_spec.rb +0 -31
  49. data/spec/unit/predicates/bool_spec.rb +0 -36
  50. data/spec/unit/predicates/bytesize_spec.rb +0 -48
  51. data/spec/unit/predicates/case_spec.rb +0 -35
  52. data/spec/unit/predicates/date_spec.rb +0 -33
  53. data/spec/unit/predicates/date_time_spec.rb +0 -33
  54. data/spec/unit/predicates/decimal_spec.rb +0 -34
  55. data/spec/unit/predicates/empty_spec.rb +0 -40
  56. data/spec/unit/predicates/eql_spec.rb +0 -23
  57. data/spec/unit/predicates/even_spec.rb +0 -33
  58. data/spec/unit/predicates/excluded_from_spec.rb +0 -37
  59. data/spec/unit/predicates/excludes_spec.rb +0 -58
  60. data/spec/unit/predicates/false_spec.rb +0 -37
  61. data/spec/unit/predicates/filled_spec.rb +0 -40
  62. data/spec/unit/predicates/float_spec.rb +0 -33
  63. data/spec/unit/predicates/format_spec.rb +0 -31
  64. data/spec/unit/predicates/gt_spec.rb +0 -42
  65. data/spec/unit/predicates/gteq_spec.rb +0 -42
  66. data/spec/unit/predicates/hash_spec.rb +0 -40
  67. data/spec/unit/predicates/included_in_spec.rb +0 -37
  68. data/spec/unit/predicates/includes_spec.rb +0 -24
  69. data/spec/unit/predicates/int_spec.rb +0 -36
  70. data/spec/unit/predicates/key_spec.rb +0 -31
  71. data/spec/unit/predicates/lt_spec.rb +0 -42
  72. data/spec/unit/predicates/lteq_spec.rb +0 -42
  73. data/spec/unit/predicates/max_bytesize_spec.rb +0 -39
  74. data/spec/unit/predicates/max_size_spec.rb +0 -51
  75. data/spec/unit/predicates/min_bytesize_spec.rb +0 -39
  76. data/spec/unit/predicates/min_size_spec.rb +0 -51
  77. data/spec/unit/predicates/none_spec.rb +0 -30
  78. data/spec/unit/predicates/not_eql_spec.rb +0 -23
  79. data/spec/unit/predicates/number_spec.rb +0 -39
  80. data/spec/unit/predicates/odd_spec.rb +0 -33
  81. data/spec/unit/predicates/respond_to_spec.rb +0 -31
  82. data/spec/unit/predicates/size_spec.rb +0 -57
  83. data/spec/unit/predicates/str_spec.rb +0 -34
  84. data/spec/unit/predicates/time_spec.rb +0 -33
  85. data/spec/unit/predicates/true_spec.rb +0 -37
  86. data/spec/unit/predicates/type_spec.rb +0 -37
  87. data/spec/unit/predicates/uuid_v4_spec.rb +0 -29
  88. data/spec/unit/predicates_spec.rb +0 -25
  89. data/spec/unit/rule/predicate_spec.rb +0 -55
  90. data/spec/unit/rule_compiler_spec.rb +0 -129
  91. data/spec/unit/rule_spec.rb +0 -213
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- if ENV['COVERAGE'] == 'true'
4
- require 'simplecov'
5
- SimpleCov.start do
6
- add_filter '/spec/'
7
- end
8
- end
9
-
10
- begin
11
- require 'pry-byebug'
12
- rescue LoadError; end
13
-
14
- require 'dry-logic'
15
- require 'dry/core/constants'
16
- require 'pathname'
17
-
18
- SPEC_ROOT = Pathname(__dir__)
19
-
20
- Dir[SPEC_ROOT.join('shared/**/*.rb')].each(&method(:require))
21
- Dir[SPEC_ROOT.join('support/**/*.rb')].each(&method(:require))
22
-
23
- include Dry::Logic
24
- include Dry::Core::Constants
25
-
26
- RSpec.configure do |config|
27
- config.disable_monkey_patching!
28
-
29
- config.warnings = true
30
- end
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Mutant
4
- class Selector
5
- class Expression < self
6
- def call(_subject)
7
- integration.all_tests
8
- end
9
- end
10
- end
11
- end
@@ -1,70 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Operations::And do
4
- subject(:operation) { Operations::And.new(left, right) }
5
-
6
- include_context 'predicates'
7
-
8
- let(:left) { Rule::Predicate.build(int?) }
9
- let(:right) { Rule::Predicate.build(gt?).curry(18) }
10
-
11
- describe '#call' do
12
- it 'calls left and right' do
13
- expect(operation.(18)).to be_failure
14
- end
15
- end
16
-
17
- describe '#to_ast' do
18
- it 'returns ast' do
19
- expect(operation.to_ast).to eql(
20
- [:and, [[:predicate, [:int?, [[:input, Undefined]]]], [:predicate, [:gt?, [[:num, 18], [:input, Undefined]]]]]]
21
- )
22
- end
23
-
24
- it 'returns result ast' do
25
- expect(operation.('18').to_ast).to eql(
26
- [:and, [[:predicate, [:int?, [[:input, '18']]]], [:hint, [:predicate, [:gt?, [[:num, 18], [:input, '18']]]]]]]
27
- )
28
-
29
- expect(operation.with(hints: false).('18').to_ast).to eql(
30
- [:predicate, [:int?, [[:input, '18']]]]
31
- )
32
-
33
- expect(operation.(18).to_ast).to eql(
34
- [:predicate, [:gt?, [[:num, 18], [:input, 18]]]]
35
- )
36
- end
37
-
38
- it 'returns failure result ast' do
39
- expect(operation.with(id: :age).('18').to_ast).to eql(
40
- [:failure, [:age, [:and, [[:predicate, [:int?, [[:input, '18']]]], [:hint, [:predicate, [:gt?, [[:num, 18], [:input, '18']]]]]]]]]
41
- )
42
-
43
- expect(operation.with(id: :age).(18).to_ast).to eql(
44
- [:failure, [:age, [:predicate, [:gt?, [[:num, 18], [:input, 18]]]]]]
45
- )
46
- end
47
- end
48
-
49
- describe '#and' do
50
- let(:other) { Rule::Predicate.build(lt?).curry(30) }
51
-
52
- it 'creates and with the other' do
53
- expect(operation.and(other).(31)).to be_failure
54
- end
55
- end
56
-
57
- describe '#or' do
58
- let(:other) { Rule::Predicate.build(lt?).curry(14) }
59
-
60
- it 'creates or with the other' do
61
- expect(operation.or(other).(13)).to be_success
62
- end
63
- end
64
-
65
- describe '#to_s' do
66
- it 'returns string representation' do
67
- expect(operation.to_s).to eql('int? AND gt?(18)')
68
- end
69
- end
70
- end
@@ -1,29 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Operations::Attr do
4
- subject(:operation) { Operations::Attr.new(Rule::Predicate.build(str?), name: :name) }
5
-
6
- include_context 'predicates'
7
-
8
- let(:model) { Struct.new(:name) }
9
-
10
- describe '#call' do
11
- it 'applies predicate to the value' do
12
- expect(operation.(model.new('Jane'))).to be_success
13
- expect(operation.(model.new(nil))).to be_failure
14
- end
15
- end
16
-
17
- describe '#and' do
18
- let(:other) { Operations::Attr.new(Rule::Predicate.build(min_size?).curry(3), name: :name) }
19
-
20
- it 'returns and where value is passed to the right' do
21
- present_and_string = operation.and(other)
22
-
23
- expect(present_and_string.(model.new('Jane'))).to be_success
24
-
25
- expect(present_and_string.(model.new('Ja'))).to be_failure
26
- expect(present_and_string.(model.new(1))).to be_failure
27
- end
28
- end
29
- end
@@ -1,51 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Operations::Check do
4
- include_context 'predicates'
5
-
6
- describe '#call' do
7
- context 'with 1-level nesting' do
8
- subject(:operation) do
9
- Operations::Check.new(Rule::Predicate.build(eql?).curry(1), id: :compare, keys: [:num])
10
- end
11
-
12
- it 'applies predicate to args extracted from the input' do
13
- expect(operation.(num: 1)).to be_success
14
- expect(operation.(num: 2)).to be_failure
15
- end
16
- end
17
-
18
- context 'with 2-levels nesting' do
19
- subject(:operation) do
20
- Operations::Check.new(Rule::Predicate.build(eql?), id: :compare, keys: [[:nums, :left], [:nums, :right]])
21
- end
22
-
23
- it 'applies predicate to args extracted from the input' do
24
- expect(operation.(nums: { left: 1, right: 1 })).to be_success
25
- expect(operation.(nums: { left: 1, right: 2 })).to be_failure
26
- end
27
-
28
- it 'curries args properly' do
29
- result = operation.(nums: { left: 1, right: 2 })
30
-
31
- expect(result.to_ast).to eql(
32
- [:failure, [:compare, [:check, [
33
- [[:nums, :left], [:nums, :right]], [:predicate, [:eql?, [[:left, 1], [:right, 2]]]]]
34
- ]]]
35
- )
36
- end
37
- end
38
- end
39
-
40
- describe '#to_ast' do
41
- subject(:operation) do
42
- Operations::Check.new(Rule::Predicate.build(str?), keys: [:email])
43
- end
44
-
45
- it 'returns ast' do
46
- expect(operation.to_ast).to eql(
47
- [:check, [[:email], [:predicate, [:str?, [[:input, Undefined]]]]]]
48
- )
49
- end
50
- end
51
- end
@@ -1,49 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Operations::Each do
4
- subject(:operation) { Operations::Each.new(is_string) }
5
-
6
- include_context 'predicates'
7
-
8
- let(:is_string) { Rule::Predicate.build(str?) }
9
-
10
- describe '#call' do
11
- it 'applies its rules to all elements in the input' do
12
- expect(operation.(['Address'])).to be_success
13
-
14
- expect(operation.([nil, 'Address'])).to be_failure
15
- expect(operation.([:Address, 'Address'])).to be_failure
16
- end
17
- end
18
-
19
- describe '#to_ast' do
20
- it 'returns ast' do
21
- expect(operation.to_ast).to eql([:each, [:predicate, [:str?, [[:input, Undefined]]]]])
22
- end
23
-
24
- it 'returns result ast' do
25
- expect(operation.([nil, 12, nil]).to_ast).to eql(
26
- [:set, [
27
- [:key, [0, [:predicate, [:str?, [[:input, nil]]]]]],
28
- [:key, [1, [:predicate, [:str?, [[:input, 12]]]]]],
29
- [:key, [2, [:predicate, [:str?, [[:input, nil]]]]]]
30
- ]]
31
- )
32
- end
33
-
34
- it 'returns failure result ast' do
35
- expect(operation.with(id: :tags).([nil, 'red', 12]).to_ast).to eql(
36
- [:failure, [:tags, [:set, [
37
- [:key, [0, [:predicate, [:str?, [[:input, nil]]]]]],
38
- [:key, [2, [:predicate, [:str?, [[:input, 12]]]]]]
39
- ]]]]
40
- )
41
- end
42
- end
43
-
44
- describe '#to_s' do
45
- it 'returns string representation' do
46
- expect(operation.to_s).to eql('each(str?)')
47
- end
48
- end
49
- end
@@ -1,32 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Operations::Implication do
4
- subject(:operation) { Operations::Implication.new(left, right) }
5
-
6
- include_context 'predicates'
7
-
8
- let(:left) { Rule::Predicate.build(int?) }
9
- let(:right) { Rule::Predicate.build(gt?).curry(18) }
10
-
11
- describe '#call' do
12
- it 'calls left and right' do
13
- expect(operation.('19')).to be_success
14
- expect(operation.(19)).to be_success
15
- expect(operation.(18)).to be_failure
16
- end
17
- end
18
-
19
- describe '#to_ast' do
20
- it 'returns ast' do
21
- expect(operation.to_ast).to eql(
22
- [:implication, [[:predicate, [:int?, [[:input, Undefined]]]], [:predicate, [:gt?, [[:num, 18], [:input, Undefined]]]]]]
23
- )
24
- end
25
- end
26
-
27
- describe '#to_s' do
28
- it 'returns string representation' do
29
- expect(operation.to_s).to eql('int? THEN gt?(18)')
30
- end
31
- end
32
- end
@@ -1,135 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Operations::Key do
4
- subject(:operation) { Operations::Key.new(predicate, name: :user) }
5
-
6
- include_context 'predicates'
7
-
8
- let(:predicate) do
9
- Rule::Predicate.build(key?).curry(:age)
10
- end
11
-
12
- describe '#call' do
13
- context 'with a plain predicate' do
14
- it 'returns a success for valid input' do
15
- expect(operation.(user: { age: 18 })).to be_success
16
- end
17
-
18
- it 'returns a failure for invalid input' do
19
- result = operation.(user: {})
20
-
21
- expect(result).to be_failure
22
-
23
- expect(result.to_ast).to eql(
24
- [:failure, [:user, [:key, [:user,
25
- [:predicate, [:key?, [[:name, :age], [:input, {}]]]]
26
- ]]]]
27
- )
28
- end
29
- end
30
-
31
- context 'with a set rule as predicate' do
32
- subject(:operation) do
33
- Operations::Key.new(predicate, name: :address)
34
- end
35
-
36
- let(:predicate) do
37
- Operations::Set.new(Rule::Predicate.build(key?).curry(:city), Rule::Predicate.build(key?).curry(:zipcode))
38
- end
39
-
40
- it 'applies set rule to the value that passes' do
41
- result = operation.(address: { city: 'NYC', zipcode: '123' })
42
-
43
- expect(result).to be_success
44
- end
45
-
46
- it 'applies set rule to the value that fails' do
47
- result = operation.(address: { city: 'NYC' })
48
-
49
- expect(result).to be_failure
50
-
51
- expect(result.to_ast).to eql(
52
- [:failure, [:address, [:key, [:address, [:set, [
53
- [:predicate, [:key?, [[:name, :zipcode], [:input, { city: 'NYC' }]]]]
54
- ]]]]]]
55
- )
56
- end
57
- end
58
-
59
- context 'with an each rule as predicate' do
60
- subject(:operation) do
61
- Operations::Key.new(predicate, name: :nums)
62
- end
63
-
64
- let(:predicate) do
65
- Operations::Each.new(Rule::Predicate.build(str?))
66
- end
67
-
68
- it 'applies each rule to the value that passses' do
69
- result = operation.(nums: %w(1 2 3))
70
-
71
- expect(result).to be_success
72
- end
73
-
74
- it 'applies each rule to the value that fails' do
75
- failure = operation.(nums: [1, '3', 3])
76
-
77
- expect(failure).to be_failure
78
-
79
- expect(failure.to_ast).to eql(
80
- [:failure, [:nums, [:key, [:nums, [:set, [
81
- [:key, [0, [:predicate, [:str?, [[:input, 1]]]]]],
82
- [:key, [2, [:predicate, [:str?, [[:input, 3]]]]]]
83
- ]]]]]]
84
- )
85
- end
86
- end
87
- end
88
-
89
- describe '#to_ast' do
90
- it 'returns ast' do
91
- expect(operation.to_ast).to eql(
92
- [:key, [:user, [:predicate, [:key?, [[:name, :age], [:input, Undefined]]]]]]
93
- )
94
- end
95
- end
96
-
97
- describe '#ast' do
98
- it 'returns ast without the input' do
99
- expect(operation.ast).to eql(
100
- [:key, [:user, [:predicate, [:key?, [[:name, :age], [:input, Undefined]]]]]]
101
- )
102
- end
103
-
104
- it 'returns ast with the input' do
105
- expect(operation.ast(user: 'jane')).to eql(
106
- [:key, [:user, [:predicate, [:key?, [[:name, :age], [:input, 'jane']]]]]]
107
- )
108
- end
109
- end
110
-
111
- describe '#and' do
112
- subject(:operation) do
113
- Operations::Key.new(Rule::Predicate.build(str?), name: [:user, :name])
114
- end
115
-
116
- let(:other) do
117
- Operations::Key.new(Rule::Predicate.build(filled?), name: [:user, :name])
118
- end
119
-
120
- it 'returns and rule where value is passed to the right' do
121
- present_and_string = operation.and(other)
122
-
123
- expect(present_and_string.(user: { name: 'Jane' })).to be_success
124
-
125
- expect(present_and_string.(user: {})).to be_failure
126
- expect(present_and_string.(user: { name: 1 })).to be_failure
127
- end
128
- end
129
-
130
- describe '#to_s' do
131
- it 'returns string representation' do
132
- expect(operation.to_s).to eql('key[user](key?(:age))')
133
- end
134
- end
135
- end
@@ -1,51 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Operations::Negation do
4
- subject(:operation) { Operations::Negation.new(is_int) }
5
-
6
- include_context 'predicates'
7
-
8
- let(:is_int) { Rule::Predicate.build(int?) }
9
-
10
- describe '#call' do
11
- it 'negates its rule' do
12
- expect(operation.('19')).to be_success
13
- expect(operation.(17)).to be_failure
14
- end
15
-
16
- context 'double negation' do
17
- subject(:double_negation) { Operations::Negation.new(operation) }
18
-
19
- it 'works as rule' do
20
- expect(double_negation.('19')).to be_failure
21
- expect(double_negation.(17)).to be_success
22
- end
23
- end
24
- end
25
-
26
- describe '#to_ast' do
27
- it 'returns ast' do
28
- expect(operation.to_ast).to eql(
29
- [:not, [:predicate, [:int?, [[:input, Undefined]]]]]
30
- )
31
- end
32
-
33
- it 'returns result ast' do
34
- expect(operation.(17).to_ast).to eql(
35
- [:not, [:predicate, [:int?, [[:input, 17]]]]]
36
- )
37
- end
38
-
39
- it 'returns result ast with an :id' do
40
- expect(operation.with(id: :age).(17).to_ast).to eql(
41
- [:failure, [:age, [:not, [:predicate, [:int?, [[:input, 17]]]]]]]
42
- )
43
- end
44
- end
45
-
46
- describe '#to_s' do
47
- it 'returns string representation' do
48
- expect(operation.to_s).to eql('not(int?)')
49
- end
50
- end
51
- end