dry-logic 1.0.4 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +113 -25
  3. data/LICENSE +1 -1
  4. data/README.md +12 -14
  5. data/dry-logic.gemspec +26 -20
  6. data/lib/dry-logic.rb +1 -1
  7. data/lib/dry/logic.rb +2 -2
  8. data/lib/dry/logic/evaluator.rb +1 -1
  9. data/lib/dry/logic/operations.rb +11 -11
  10. data/lib/dry/logic/operations/abstract.rb +3 -3
  11. data/lib/dry/logic/operations/and.rb +3 -3
  12. data/lib/dry/logic/operations/attr.rb +1 -1
  13. data/lib/dry/logic/operations/binary.rb +1 -1
  14. data/lib/dry/logic/operations/check.rb +3 -3
  15. data/lib/dry/logic/operations/each.rb +2 -2
  16. data/lib/dry/logic/operations/implication.rb +2 -2
  17. data/lib/dry/logic/operations/key.rb +3 -3
  18. data/lib/dry/logic/operations/negation.rb +2 -2
  19. data/lib/dry/logic/operations/or.rb +2 -2
  20. data/lib/dry/logic/operations/set.rb +3 -3
  21. data/lib/dry/logic/operations/unary.rb +1 -1
  22. data/lib/dry/logic/operations/xor.rb +2 -2
  23. data/lib/dry/logic/operators.rb +4 -4
  24. data/lib/dry/logic/predicates.rb +33 -8
  25. data/lib/dry/logic/result.rb +2 -2
  26. data/lib/dry/logic/rule.rb +8 -8
  27. data/lib/dry/logic/rule/interface.rb +32 -37
  28. data/lib/dry/logic/rule/predicate.rb +3 -3
  29. data/lib/dry/logic/rule_compiler.rb +3 -3
  30. data/lib/dry/logic/version.rb +1 -1
  31. metadata +17 -166
  32. data/.codeclimate.yml +0 -12
  33. data/.github/ISSUE_TEMPLATE/----please-don-t-ask-for-support-via-issues.md +0 -10
  34. data/.github/ISSUE_TEMPLATE/---bug-report.md +0 -34
  35. data/.github/ISSUE_TEMPLATE/---feature-request.md +0 -18
  36. data/.github/workflows/ci.yml +0 -70
  37. data/.github/workflows/docsite.yml +0 -34
  38. data/.github/workflows/sync_configs.yml +0 -34
  39. data/.gitignore +0 -9
  40. data/.rspec +0 -4
  41. data/.rubocop.yml +0 -89
  42. data/CODE_OF_CONDUCT.md +0 -13
  43. data/CONTRIBUTING.md +0 -29
  44. data/Gemfile +0 -16
  45. data/Rakefile +0 -14
  46. data/benchmarks/rule_application.rb +0 -30
  47. data/benchmarks/setup.rb +0 -13
  48. data/bin/console +0 -11
  49. data/docsite/source/index.html.md +0 -54
  50. data/docsite/source/operations.html.md +0 -62
  51. data/docsite/source/predicates.html.md +0 -102
  52. data/examples/basic.rb +0 -16
  53. data/spec/integration/result_spec.rb +0 -61
  54. data/spec/integration/rule_spec.rb +0 -55
  55. data/spec/shared/predicates.rb +0 -59
  56. data/spec/shared/rule.rb +0 -74
  57. data/spec/spec_helper.rb +0 -30
  58. data/spec/support/mutant.rb +0 -11
  59. data/spec/unit/operations/and_spec.rb +0 -70
  60. data/spec/unit/operations/attr_spec.rb +0 -29
  61. data/spec/unit/operations/check_spec.rb +0 -51
  62. data/spec/unit/operations/each_spec.rb +0 -49
  63. data/spec/unit/operations/implication_spec.rb +0 -32
  64. data/spec/unit/operations/key_spec.rb +0 -135
  65. data/spec/unit/operations/negation_spec.rb +0 -51
  66. data/spec/unit/operations/or_spec.rb +0 -75
  67. data/spec/unit/operations/set_spec.rb +0 -43
  68. data/spec/unit/operations/xor_spec.rb +0 -63
  69. data/spec/unit/predicates/array_spec.rb +0 -43
  70. data/spec/unit/predicates/attr_spec.rb +0 -31
  71. data/spec/unit/predicates/bool_spec.rb +0 -36
  72. data/spec/unit/predicates/bytesize_spec.rb +0 -48
  73. data/spec/unit/predicates/case_spec.rb +0 -35
  74. data/spec/unit/predicates/date_spec.rb +0 -33
  75. data/spec/unit/predicates/date_time_spec.rb +0 -33
  76. data/spec/unit/predicates/decimal_spec.rb +0 -34
  77. data/spec/unit/predicates/empty_spec.rb +0 -40
  78. data/spec/unit/predicates/eql_spec.rb +0 -23
  79. data/spec/unit/predicates/even_spec.rb +0 -33
  80. data/spec/unit/predicates/excluded_from_spec.rb +0 -37
  81. data/spec/unit/predicates/excludes_spec.rb +0 -58
  82. data/spec/unit/predicates/false_spec.rb +0 -37
  83. data/spec/unit/predicates/filled_spec.rb +0 -40
  84. data/spec/unit/predicates/float_spec.rb +0 -33
  85. data/spec/unit/predicates/format_spec.rb +0 -23
  86. data/spec/unit/predicates/gt_spec.rb +0 -42
  87. data/spec/unit/predicates/gteq_spec.rb +0 -42
  88. data/spec/unit/predicates/hash_spec.rb +0 -40
  89. data/spec/unit/predicates/included_in_spec.rb +0 -37
  90. data/spec/unit/predicates/includes_spec.rb +0 -24
  91. data/spec/unit/predicates/int_spec.rb +0 -36
  92. data/spec/unit/predicates/key_spec.rb +0 -31
  93. data/spec/unit/predicates/lt_spec.rb +0 -42
  94. data/spec/unit/predicates/lteq_spec.rb +0 -42
  95. data/spec/unit/predicates/max_bytesize_spec.rb +0 -39
  96. data/spec/unit/predicates/max_size_spec.rb +0 -51
  97. data/spec/unit/predicates/min_bytesize_spec.rb +0 -39
  98. data/spec/unit/predicates/min_size_spec.rb +0 -51
  99. data/spec/unit/predicates/none_spec.rb +0 -30
  100. data/spec/unit/predicates/not_eql_spec.rb +0 -23
  101. data/spec/unit/predicates/number_spec.rb +0 -39
  102. data/spec/unit/predicates/odd_spec.rb +0 -33
  103. data/spec/unit/predicates/respond_to_spec.rb +0 -31
  104. data/spec/unit/predicates/size_spec.rb +0 -57
  105. data/spec/unit/predicates/str_spec.rb +0 -34
  106. data/spec/unit/predicates/time_spec.rb +0 -33
  107. data/spec/unit/predicates/true_spec.rb +0 -37
  108. data/spec/unit/predicates/type_spec.rb +0 -37
  109. data/spec/unit/predicates/uuid_v4_spec.rb +0 -29
  110. data/spec/unit/predicates_spec.rb +0 -25
  111. data/spec/unit/rule/predicate_spec.rb +0 -55
  112. data/spec/unit/rule_compiler_spec.rb +0 -129
  113. data/spec/unit/rule_spec.rb +0 -213
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/core/constants'
4
- require 'dry/equalizer'
5
- require 'dry/logic/operators'
3
+ require "dry/core/constants"
4
+ require "dry/core/equalizer"
5
+ require "dry/logic/operators"
6
6
 
7
7
  module Dry
8
8
  module Logic
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/logic/operations/binary'
4
- require 'dry/logic/result'
3
+ require "dry/logic/operations/binary"
4
+ require "dry/logic/result"
5
5
 
6
6
  module Dry
7
7
  module Logic
@@ -17,7 +17,7 @@ module Dry
17
17
  def type
18
18
  :and
19
19
  end
20
- alias operator type
20
+ alias_method :operator, :type
21
21
 
22
22
  def call(input)
23
23
  left_result = left.(input)
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/logic/operations/key'
3
+ require "dry/logic/operations/key"
4
4
 
5
5
  module Dry
6
6
  module Logic
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/logic/operations/abstract'
3
+ require "dry/logic/operations/abstract"
4
4
 
5
5
  module Dry
6
6
  module Logic
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/logic/operations/unary'
4
- require 'dry/logic/evaluator'
5
- require 'dry/logic/result'
3
+ require "dry/logic/operations/unary"
4
+ require "dry/logic/evaluator"
5
+ require "dry/logic/result"
6
6
 
7
7
  module Dry
8
8
  module Logic
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/logic/operations/unary'
4
- require 'dry/logic/result'
3
+ require "dry/logic/operations/unary"
4
+ require "dry/logic/result"
5
5
 
6
6
  module Dry
7
7
  module Logic
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/logic/operations/binary'
4
- require 'dry/logic/result'
3
+ require "dry/logic/operations/binary"
4
+ require "dry/logic/result"
5
5
 
6
6
  module Dry
7
7
  module Logic
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/logic/operations/unary'
4
- require 'dry/logic/evaluator'
5
- require 'dry/logic/result'
3
+ require "dry/logic/operations/unary"
4
+ require "dry/logic/evaluator"
5
+ require "dry/logic/result"
6
6
 
7
7
  module Dry
8
8
  module Logic
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/logic/operations/unary'
4
- require 'dry/logic/result'
3
+ require "dry/logic/operations/unary"
4
+ require "dry/logic/result"
5
5
 
6
6
  module Dry
7
7
  module Logic
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/logic/operations/binary'
4
- require 'dry/logic/result'
3
+ require "dry/logic/operations/binary"
4
+ require "dry/logic/result"
5
5
 
6
6
  module Dry
7
7
  module Logic
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/logic/operations/abstract'
4
- require 'dry/logic/result'
3
+ require "dry/logic/operations/abstract"
4
+ require "dry/logic/result"
5
5
 
6
6
  module Dry
7
7
  module Logic
@@ -29,7 +29,7 @@ module Dry
29
29
  end
30
30
 
31
31
  def to_s
32
- "#{type}(#{rules.map(&:to_s).join(', ')})"
32
+ "#{type}(#{rules.map(&:to_s).join(", ")})"
33
33
  end
34
34
  end
35
35
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/logic/operations/abstract'
3
+ require "dry/logic/operations/abstract"
4
4
 
5
5
  module Dry
6
6
  module Logic
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/logic/operations/binary'
4
- require 'dry/logic/result'
3
+ require "dry/logic/operations/binary"
4
+ require "dry/logic/result"
5
5
 
6
6
  module Dry
7
7
  module Logic
@@ -6,22 +6,22 @@ module Dry
6
6
  def and(other)
7
7
  Operations::And.new(self, other)
8
8
  end
9
- alias & and
9
+ alias_method :&, :and
10
10
 
11
11
  def or(other)
12
12
  Operations::Or.new(self, other)
13
13
  end
14
- alias | or
14
+ alias_method :|, :or
15
15
 
16
16
  def xor(other)
17
17
  Operations::Xor.new(self, other)
18
18
  end
19
- alias ^ xor
19
+ alias_method :^, :xor
20
20
 
21
21
  def then(other)
22
22
  Operations::Implication.new(self, other)
23
23
  end
24
- alias > then
24
+ alias_method :>, :then
25
25
  end
26
26
  end
27
27
  end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'bigdecimal'
4
- require 'bigdecimal/util'
5
- require 'date'
3
+ require "bigdecimal"
4
+ require "bigdecimal/util"
5
+ require "date"
6
6
 
7
7
  module Dry
8
8
  module Logic
@@ -13,7 +13,7 @@ module Dry
13
13
  end
14
14
 
15
15
  def type?(type, input)
16
- input.kind_of?(type)
16
+ input.is_a?(type)
17
17
  end
18
18
 
19
19
  def nil?(input)
@@ -147,12 +147,12 @@ module Dry
147
147
  end
148
148
 
149
149
  def inclusion?(list, input)
150
- ::Kernel.warn 'inclusion is deprecated - use included_in instead.'
150
+ ::Kernel.warn "inclusion is deprecated - use included_in instead."
151
151
  included_in?(list, input)
152
152
  end
153
153
 
154
154
  def exclusion?(list, input)
155
- ::Kernel.warn 'exclusion is deprecated - use excluded_from instead.'
155
+ ::Kernel.warn "exclusion is deprecated - use excluded_from instead."
156
156
  excluded_from?(list, input)
157
157
  end
158
158
 
@@ -199,18 +199,43 @@ module Dry
199
199
  end
200
200
 
201
201
  def format?(regex, input)
202
- regex.match?(input)
202
+ !input.nil? && regex.match?(input)
203
203
  end
204
204
 
205
205
  def case?(pattern, input)
206
206
  pattern === input
207
207
  end
208
208
 
209
+ def uuid_v1?(input)
210
+ uuid_v1_format = /\A[0-9A-F]{8}-[0-9A-F]{4}-1[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}\z/i
211
+ format?(uuid_v1_format, input)
212
+ end
213
+
214
+ def uuid_v2?(input)
215
+ uuid_v2_format = /\A[0-9A-F]{8}-[0-9A-F]{4}-2[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}\z/i
216
+ format?(uuid_v2_format, input)
217
+ end
218
+
219
+ def uuid_v3?(input)
220
+ uuid_v3_format = /\A[0-9A-F]{8}-[0-9A-F]{4}-3[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}\z/i
221
+ format?(uuid_v3_format, input)
222
+ end
223
+
209
224
  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
225
+ uuid_v4_format = /\A[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}\z/i
211
226
  format?(uuid_v4_format, input)
212
227
  end
213
228
 
229
+ def uuid_v5?(input)
230
+ uuid_v5_format = /\A[0-9A-F]{8}-[0-9A-F]{4}-5[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}\z/i
231
+ format?(uuid_v5_format, input)
232
+ end
233
+
234
+ def uri?(schemes, input)
235
+ uri_format = URI::DEFAULT_PARSER.make_regexp(schemes)
236
+ format?(uri_format, input)
237
+ end
238
+
214
239
  def respond_to?(method, input)
215
240
  input.respond_to?(method)
216
241
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/core/constants'
3
+ require "dry/core/constants"
4
4
 
5
5
  module Dry
6
6
  module Logic
@@ -69,7 +69,7 @@ module Dry
69
69
  if args.empty?
70
70
  name.to_s
71
71
  else
72
- "#{name}(#{args.map(&:last).map(&:inspect).join(', ')})"
72
+ "#{name}(#{args.map(&:last).map(&:inspect).join(", ")})"
73
73
  end
74
74
  end
75
75
 
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'concurrent/map'
4
- require 'dry/core/constants'
5
- require 'dry/equalizer'
6
- require 'dry/logic/operations'
7
- require 'dry/logic/result'
8
- require 'dry/logic/rule/interface'
3
+ require "concurrent/map"
4
+ require "dry/core/constants"
5
+ require "dry/core/equalizer"
6
+ require "dry/logic/operations"
7
+ require "dry/logic/result"
8
+ require "dry/logic/rule/interface"
9
9
 
10
10
  module Dry
11
11
  module Logic
@@ -38,13 +38,13 @@ module Dry
38
38
  base.interfaces.fetch_or_store([arity, curried]) do
39
39
  interface = Interface.new(arity, curried)
40
40
  klass = Class.new(base) { include interface }
41
- base.const_set("#{base.name.split('::').last}#{interface.name}", klass)
41
+ base.const_set("#{base.name.split("::").last}#{interface.name}", klass)
42
42
  klass
43
43
  end
44
44
  end
45
45
 
46
46
  def self.build(predicate, args: EMPTY_ARRAY, arity: predicate.arity, **options)
47
- specialize(arity, args.size).new(predicate, { args: args, arity: arity, **options })
47
+ specialize(arity, args.size).new(predicate, {args: args, arity: arity, **options})
48
48
  end
49
49
 
50
50
  def initialize(predicate, options = EMPTY_HASH)
@@ -4,6 +4,8 @@ module Dry
4
4
  module Logic
5
5
  class Rule
6
6
  class Interface < ::Module
7
+ SPLAT = ["*rest"].freeze
8
+
7
9
  attr_reader :arity
8
10
 
9
11
  attr_reader :curried
@@ -18,12 +20,10 @@ module Dry
18
20
 
19
21
  define_constructor if curried?
20
22
 
21
- if variable_arity?
22
- define_splat_application
23
- elsif constant?
23
+ if constant?
24
24
  define_constant_application
25
25
  else
26
- define_fixed_application
26
+ define_application
27
27
  end
28
28
  end
29
29
 
@@ -32,7 +32,7 @@ module Dry
32
32
  end
33
33
 
34
34
  def variable_arity?
35
- arity.equal?(-1)
35
+ arity.negative?
36
36
  end
37
37
 
38
38
  def curried?
@@ -41,7 +41,13 @@ module Dry
41
41
 
42
42
  def unapplied
43
43
  if variable_arity?
44
- -1
44
+ unapplied = arity.abs - 1 - curried
45
+
46
+ if unapplied.negative?
47
+ 0
48
+ else
49
+ unapplied
50
+ end
45
51
  else
46
52
  arity - curried
47
53
  end
@@ -49,10 +55,21 @@ module Dry
49
55
 
50
56
  def name
51
57
  if constant?
52
- 'Constant'
58
+ "Constant"
53
59
  else
54
- arity_str = variable_arity? ? 'VariableArity' : "#{arity}Arity"
55
- curried_str = curried? ? "#{curried}Curried" : EMPTY_STRING
60
+ arity_str =
61
+ if variable_arity?
62
+ "Variable#{arity.abs - 1}Arity"
63
+ else
64
+ "#{arity}Arity"
65
+ end
66
+
67
+ curried_str =
68
+ if curried?
69
+ "#{curried}Curried"
70
+ else
71
+ EMPTY_STRING
72
+ end
56
73
 
57
74
  "#{arity_str}#{curried_str}"
58
75
  end
@@ -61,9 +78,9 @@ module Dry
61
78
  def define_constructor
62
79
  assignment =
63
80
  if curried.equal?(1)
64
- '@arg0 = @args[0]'
81
+ "@arg0 = @args[0]"
65
82
  else
66
- "#{curried_args.join(', ')} = @args"
83
+ "#{curried_args.join(", ")} = @args"
67
84
  end
68
85
 
69
86
  module_eval(<<~RUBY, __FILE__, __LINE__ + 1)
@@ -91,32 +108,10 @@ module Dry
91
108
  end
92
109
  end
93
110
 
94
- def define_splat_application
95
- application =
96
- if curried?
97
- "@predicate[#{curried_args.join(', ')}, *input]"
98
- else
99
- '@predicate[*input]'
100
- end
101
-
102
- module_eval(<<~RUBY, __FILE__, __LINE__ + 1)
103
- def call(*input)
104
- if #{application}
105
- Result::SUCCESS
106
- else
107
- Result.new(false, id) { ast(*input) }
108
- end
109
- end
110
-
111
- def [](*input)
112
- #{application}
113
- end
114
- RUBY
115
- end
116
-
117
- def define_fixed_application
118
- parameters = unapplied_args.join(', ')
119
- application = "@predicate[#{ (curried_args + unapplied_args).join(', ') }]"
111
+ def define_application
112
+ splat = variable_arity? ? SPLAT : EMPTY_ARRAY
113
+ parameters = (unapplied_args + splat).join(", ")
114
+ application = "@predicate[#{(curried_args + unapplied_args + splat).join(", ")}]"
120
115
 
121
116
  module_eval(<<~RUBY, __FILE__, __LINE__ + 1)
122
117
  def call(#{parameters})
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/logic/rule'
3
+ require "dry/logic/rule"
4
4
 
5
5
  module Dry
6
6
  module Logic
@@ -19,9 +19,9 @@ module Dry
19
19
 
20
20
  def to_s
21
21
  if args.size > 0
22
- "#{name}(#{args.map(&:inspect).join(', ')})"
22
+ "#{name}(#{args.map(&:inspect).join(", ")})"
23
23
  else
24
- "#{name}"
24
+ name.to_s
25
25
  end
26
26
  end
27
27