dry-logic 0.5.0 → 0.6.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/.codeclimate.yml +13 -21
- data/.gitignore +1 -0
- data/.travis.yml +9 -8
- data/CHANGELOG.md +12 -0
- data/Gemfile +3 -7
- data/README.md +3 -3
- data/benchmarks/rule_application.rb +28 -0
- data/benchmarks/setup.rb +11 -0
- data/dry-logic.gemspec +1 -1
- data/examples/basic.rb +2 -2
- data/lib/dry/logic/operations/and.rb +12 -2
- data/lib/dry/logic/rule.rb +28 -25
- data/lib/dry/logic/rule/interface.rb +126 -0
- data/lib/dry/logic/rule/predicate.rb +4 -0
- data/lib/dry/logic/rule_compiler.rb +1 -1
- data/lib/dry/logic/version.rb +1 -1
- data/spec/integration/result_spec.rb +6 -6
- data/spec/shared/rule.rb +13 -8
- data/spec/spec_helper.rb +1 -1
- data/spec/unit/operations/and_spec.rb +8 -4
- data/spec/unit/operations/attr_spec.rb +2 -2
- data/spec/unit/operations/check_spec.rb +3 -3
- data/spec/unit/operations/each_spec.rb +1 -1
- data/spec/unit/operations/implication_spec.rb +2 -2
- data/spec/unit/operations/key_spec.rb +5 -5
- data/spec/unit/operations/negation_spec.rb +1 -1
- data/spec/unit/operations/or_spec.rb +3 -3
- data/spec/unit/operations/set_spec.rb +2 -2
- data/spec/unit/operations/xor_spec.rb +3 -3
- data/spec/unit/rule/predicate_spec.rb +4 -4
- data/spec/unit/rule_compiler_spec.rb +1 -1
- data/spec/unit/rule_spec.rb +70 -9
- metadata +10 -15
- data/.rubocop.yml +0 -16
- data/.rubocop_todo.yml +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 12cf783095366932df786fea023d69be64d48e7b91c03a279186d9be7ed098b4
|
4
|
+
data.tar.gz: e324cfb405828951649cd948055dc4fbfb84eb65f50156cee29695785d8b065f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 476e8b141e0868cc3bdcdee4c7d695809ae056d6b7977b0b49db6af47990a1a285b33350ef6a789670576d64bcb8495b0068228a812d6a7727b98250445c1485
|
7
|
+
data.tar.gz: c3de162dc7c3f75b7ee0c2e321406cc9e9f5f17d0e73c7ef416bb40981b037ce3c4c846a9f55cb5a3602ae3deb2a4162e3a502c20f87cd1009b97f4c8ecdc690
|
data/.codeclimate.yml
CHANGED
@@ -1,23 +1,15 @@
|
|
1
|
-
|
1
|
+
version: "2"
|
2
|
+
|
3
|
+
prepare:
|
4
|
+
fetch:
|
5
|
+
- url: "https://raw.githubusercontent.com/dry-rb/devtools/master/.rubocop.yml"
|
6
|
+
path: ".rubocop.yml"
|
7
|
+
|
8
|
+
exclude_patterns:
|
9
|
+
- "benchmarks/"
|
10
|
+
- "examples/"
|
11
|
+
- "spec/"
|
12
|
+
|
13
|
+
plugins:
|
2
14
|
rubocop:
|
3
15
|
enabled: true
|
4
|
-
checks:
|
5
|
-
Rubocop/Metrics/LineLength:
|
6
|
-
enabled: true
|
7
|
-
max: 100
|
8
|
-
Rubocop/Style/Documentation:
|
9
|
-
enabled: false
|
10
|
-
Rubocop/Lint/HandleExceptions:
|
11
|
-
enabled: true
|
12
|
-
exclude:
|
13
|
-
- rakelib/*.rake
|
14
|
-
Rubocop/Style/FileName:
|
15
|
-
enabled: true
|
16
|
-
exclude:
|
17
|
-
- 'lib/dry-logic.rb'
|
18
|
-
ratings:
|
19
|
-
paths:
|
20
|
-
- lib/**/*.rb
|
21
|
-
exclude_paths:
|
22
|
-
- spec/**/*
|
23
|
-
- examples/**/*
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
language: ruby
|
2
2
|
cache: bundler
|
3
|
-
sudo: false
|
4
3
|
bundler_args: --without benchmarks tools
|
5
|
-
before_install: gem update --system
|
6
4
|
before_script:
|
7
5
|
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
8
6
|
- chmod +x ./cc-test-reporter
|
@@ -12,19 +10,22 @@ after_script:
|
|
12
10
|
script:
|
13
11
|
- bundle exec rake
|
14
12
|
rvm:
|
15
|
-
- 2.6.
|
16
|
-
- 2.5.
|
17
|
-
- 2.4.
|
18
|
-
- 2.
|
19
|
-
-
|
13
|
+
- 2.6.2
|
14
|
+
- 2.5.5
|
15
|
+
- 2.4.6
|
16
|
+
- jruby-9.2.6.0
|
17
|
+
- truffleruby
|
20
18
|
env:
|
21
19
|
global:
|
22
20
|
- COVERAGE=true
|
21
|
+
matrix:
|
22
|
+
allow_failures:
|
23
|
+
- rvm: truffleruby
|
23
24
|
notifications:
|
24
25
|
email: false
|
25
26
|
webhooks:
|
26
27
|
urls:
|
27
|
-
- https://
|
28
|
+
- https://dry-rb.zulipchat.com/api/v1/external/travis?api_key=SY8LLz6fShd4TJeLDXEdT0eBEgRqT2lv&stream=notifications&topic=ci
|
28
29
|
on_success: change # options: [always|never|change] default: always
|
29
30
|
on_failure: always # options: [always|never|change] default: always
|
30
31
|
on_start: false # default: false
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
# v0.6.0 2019-04-04
|
2
|
+
|
3
|
+
### Added
|
4
|
+
|
5
|
+
* Generating hints can be disabled by building `Operations::And` with `hints: false` option set (solnic)
|
6
|
+
|
7
|
+
### Changed
|
8
|
+
|
9
|
+
* `Rule` construction has been optimized so that currying and application is multiple-times faster (flash-gordon)
|
10
|
+
|
11
|
+
[Compare v0.5.0...v0.6.0](https://github.com/dry-rb/dry-logic/compare/v0.5.0...v0.6.0)
|
12
|
+
|
1
13
|
# v0.5.0 2019-01-29
|
2
14
|
|
3
15
|
### Added
|
data/Gemfile
CHANGED
@@ -7,11 +7,7 @@ group :test do
|
|
7
7
|
end
|
8
8
|
|
9
9
|
group :tools do
|
10
|
-
gem '
|
11
|
-
gem '
|
12
|
-
|
13
|
-
unless ENV['TRAVIS']
|
14
|
-
gem 'mutant', github: 'mbj/mutant'
|
15
|
-
gem 'mutant-rspec', github: 'mbj/mutant'
|
16
|
-
end
|
10
|
+
gem 'pry-byebug', platform: :mri
|
11
|
+
gem 'benchmark-ips', platform: :mri
|
12
|
+
gem 'hotch', platform: :mri
|
17
13
|
end
|
data/README.md
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
[gem]: https://rubygems.org/gems/dry-logic
|
2
2
|
[travis]: https://travis-ci.org/dry-rb/dry-logic
|
3
3
|
[codeclimate]: https://codeclimate.com/github/dry-rb/dry-logic
|
4
|
-
[
|
4
|
+
[chat]: https://dry-rb.zulipchat.com
|
5
5
|
[inchpages]: http://inch-ci.org/github/dry-rb/dry-logic
|
6
6
|
|
7
|
-
# dry-
|
7
|
+
# dry-schema [][chat]
|
8
8
|
|
9
9
|
[][gem]
|
10
10
|
[][travis]
|
@@ -15,7 +15,7 @@
|
|
15
15
|
Predicate logic and rule composition used by:
|
16
16
|
|
17
17
|
* [dry-types](https://github.com/dry-rb/dry-types) for constrained types
|
18
|
-
* [dry-validation](https://github.com/dry-rb/dry-validation) for composing validation rules
|
18
|
+
* [dry-schema](https://github.com/dry-rb/dry-schema) and [dry-validation](https://github.com/dry-rb/dry-validation) for composing validation rules
|
19
19
|
* your project...?
|
20
20
|
|
21
21
|
## Links
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require_relative 'setup'
|
2
|
+
|
3
|
+
unless Dry::Logic::Rule.respond_to?(:build)
|
4
|
+
Dry::Logic::Rule.singleton_class.alias_method(:build, :new)
|
5
|
+
end
|
6
|
+
|
7
|
+
predicates = Dry::Logic::Predicates
|
8
|
+
|
9
|
+
type_check = Dry::Logic::Rule.build(predicates[:type?]).curry(Integer)
|
10
|
+
int_check = Dry::Logic::Rule.build(predicates[:int?])
|
11
|
+
key_check = Dry::Logic::Rule.build(predicates[:key?]).curry(:user)
|
12
|
+
with_user = { user: {} }
|
13
|
+
without_user = {}
|
14
|
+
|
15
|
+
comparison = Dry::Logic::Rule.build(predicates[:gteq?]).curry(18)
|
16
|
+
|
17
|
+
Benchmark.ips do |x|
|
18
|
+
x.report("type check - success") { type_check.(0) }
|
19
|
+
x.report("type check - failure") { type_check.('0') }
|
20
|
+
x.report("int check - success") { int_check.(0) }
|
21
|
+
x.report("int check - failure") { int_check.('0') }
|
22
|
+
x.report("key check - success") { key_check.(with_user) }
|
23
|
+
x.report("key check - failure") { key_check.(without_user) }
|
24
|
+
x.report("comparison - success") { comparison.(20) }
|
25
|
+
x.report("comparison - failure") { comparison.(17) }
|
26
|
+
|
27
|
+
x.compare!
|
28
|
+
end
|
data/benchmarks/setup.rb
ADDED
data/dry-logic.gemspec
CHANGED
@@ -13,8 +13,8 @@ Gem::Specification.new do |spec|
|
|
13
13
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
14
14
|
spec.require_paths = ['lib']
|
15
15
|
|
16
|
+
spec.add_runtime_dependency 'concurrent-ruby', '~> 1.0'
|
16
17
|
spec.add_runtime_dependency 'dry-core', '~> 0.2'
|
17
|
-
spec.add_runtime_dependency 'dry-container', '~> 0.2', '>= 0.2.6'
|
18
18
|
spec.add_runtime_dependency 'dry-equalizer', '~> 0.2'
|
19
19
|
|
20
20
|
spec.add_development_dependency 'bundler'
|
data/examples/basic.rb
CHANGED
@@ -3,9 +3,9 @@ require 'dry/logic/predicates'
|
|
3
3
|
|
4
4
|
include Dry::Logic
|
5
5
|
|
6
|
-
user_present = Rule::Predicate.
|
6
|
+
user_present = Rule::Predicate.build(Predicates[:key?]).curry(:user)
|
7
7
|
|
8
|
-
has_min_age = Operations::Key.new(Rule::Predicate.
|
8
|
+
has_min_age = Operations::Key.new(Rule::Predicate.build(Predicates[:gt?]).curry(18), name: [:user, :age])
|
9
9
|
|
10
10
|
user_rule = user_present & has_min_age
|
11
11
|
|
@@ -5,10 +5,17 @@ module Dry
|
|
5
5
|
module Logic
|
6
6
|
module Operations
|
7
7
|
class And < Binary
|
8
|
+
attr_reader :hints
|
9
|
+
|
10
|
+
def initialize(*)
|
11
|
+
super
|
12
|
+
@hints = options.fetch(:hints, true)
|
13
|
+
end
|
14
|
+
|
8
15
|
def type
|
9
16
|
:and
|
10
17
|
end
|
11
|
-
|
18
|
+
alias operator type
|
12
19
|
|
13
20
|
def call(input)
|
14
21
|
left_result = left.(input)
|
@@ -22,7 +29,10 @@ module Dry
|
|
22
29
|
Result.new(false, id) { right_result.ast(input) }
|
23
30
|
end
|
24
31
|
else
|
25
|
-
Result.new(false, id)
|
32
|
+
Result.new(false, id) do
|
33
|
+
left_ast = left_result.to_ast
|
34
|
+
hints ? [type, [left_ast, [:hint, right.ast(input)]]] : left_ast
|
35
|
+
end
|
26
36
|
end
|
27
37
|
end
|
28
38
|
|
data/lib/dry/logic/rule.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
|
+
require 'concurrent/map'
|
1
2
|
require 'dry/core/constants'
|
2
3
|
require 'dry/equalizer'
|
3
4
|
require 'dry/logic/operations'
|
4
5
|
require 'dry/logic/result'
|
6
|
+
require 'dry/logic/rule/interface'
|
5
7
|
|
6
8
|
module Dry
|
7
9
|
module Logic
|
8
10
|
def self.Rule(*args, **options, &block)
|
9
11
|
if args.any?
|
10
|
-
Rule.
|
12
|
+
Rule.build(*args, **options)
|
11
13
|
elsif block
|
12
|
-
Rule.
|
14
|
+
Rule.build(block, **options)
|
13
15
|
end
|
14
16
|
end
|
15
17
|
|
@@ -18,8 +20,6 @@ module Dry
|
|
18
20
|
include Dry::Equalizer(:predicate, :options)
|
19
21
|
include Operators
|
20
22
|
|
21
|
-
DEFAULT_OPTIONS = { args: [].freeze }.freeze
|
22
|
-
|
23
23
|
attr_reader :predicate
|
24
24
|
|
25
25
|
attr_reader :options
|
@@ -28,10 +28,27 @@ module Dry
|
|
28
28
|
|
29
29
|
attr_reader :arity
|
30
30
|
|
31
|
-
def
|
31
|
+
def self.interfaces
|
32
|
+
@interfaces ||= ::Concurrent::Map.new
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.specialize(arity, curried, base = Rule)
|
36
|
+
base.interfaces.fetch_or_store([arity, curried]) do
|
37
|
+
interface = Interface.new(arity, curried)
|
38
|
+
klass = Class.new(base) { include interface }
|
39
|
+
base.const_set("#{base.name.split('::').last}#{interface.name}", klass)
|
40
|
+
klass
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.build(predicate, args: EMPTY_ARRAY, arity: predicate.arity, **options)
|
45
|
+
specialize(arity, args.size).new(predicate, { args: args, arity: arity, **options })
|
46
|
+
end
|
47
|
+
|
48
|
+
def initialize(predicate, options = EMPTY_HASH)
|
32
49
|
@predicate = predicate
|
33
50
|
@options = options
|
34
|
-
@args = options[:args]
|
51
|
+
@args = options[:args] || EMPTY_ARRAY
|
35
52
|
@arity = options[:arity] || predicate.arity
|
36
53
|
end
|
37
54
|
|
@@ -43,29 +60,15 @@ module Dry
|
|
43
60
|
options[:id]
|
44
61
|
end
|
45
62
|
|
46
|
-
def call(*input)
|
47
|
-
Result.new(self[*input], id) { ast(*input) }
|
48
|
-
end
|
49
|
-
|
50
|
-
def [](*input)
|
51
|
-
arity == 0 ? predicate.() : predicate[*args, *input]
|
52
|
-
end
|
53
|
-
|
54
63
|
def curry(*new_args)
|
55
|
-
|
56
|
-
|
57
|
-
if all_args.size > arity
|
58
|
-
raise ArgumentError, "wrong number of arguments (#{all_args.size} for #{arity})"
|
59
|
-
else
|
60
|
-
with(args: all_args)
|
61
|
-
end
|
64
|
+
with(args: args + new_args)
|
62
65
|
end
|
63
66
|
|
64
67
|
def bind(object)
|
65
|
-
if
|
66
|
-
self.class.
|
68
|
+
if predicate.respond_to?(:bind)
|
69
|
+
self.class.build(predicate.bind(object), options)
|
67
70
|
else
|
68
|
-
self.class.
|
71
|
+
self.class.build(
|
69
72
|
-> *args { object.instance_exec(*args, &predicate) },
|
70
73
|
options.merge(arity: arity, parameters: parameters)
|
71
74
|
)
|
@@ -77,7 +80,7 @@ module Dry
|
|
77
80
|
end
|
78
81
|
|
79
82
|
def with(new_opts)
|
80
|
-
self.class.
|
83
|
+
self.class.build(predicate, options.merge(new_opts))
|
81
84
|
end
|
82
85
|
|
83
86
|
def parameters
|
@@ -0,0 +1,126 @@
|
|
1
|
+
module Dry
|
2
|
+
module Logic
|
3
|
+
class Rule
|
4
|
+
class Interface < ::Module
|
5
|
+
attr_reader :arity
|
6
|
+
|
7
|
+
attr_reader :curried
|
8
|
+
|
9
|
+
def initialize(arity, curried)
|
10
|
+
@arity = arity
|
11
|
+
@curried = curried
|
12
|
+
|
13
|
+
if !variable_arity? && curried > arity
|
14
|
+
raise ArgumentError, "wrong number of arguments (#{curried} for #{arity})"
|
15
|
+
end
|
16
|
+
|
17
|
+
define_constructor if curried?
|
18
|
+
|
19
|
+
if variable_arity?
|
20
|
+
define_splat_application
|
21
|
+
else
|
22
|
+
define_fixed_application
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def constant?
|
27
|
+
arity.zero?
|
28
|
+
end
|
29
|
+
|
30
|
+
def variable_arity?
|
31
|
+
arity.equal?(-1)
|
32
|
+
end
|
33
|
+
|
34
|
+
def curried?
|
35
|
+
!curried.zero?
|
36
|
+
end
|
37
|
+
|
38
|
+
def unapplied
|
39
|
+
if variable_arity?
|
40
|
+
-1
|
41
|
+
else
|
42
|
+
arity - curried
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def name
|
47
|
+
if constant?
|
48
|
+
'Constant'
|
49
|
+
else
|
50
|
+
arity_str = variable_arity? ? 'VariableArity' : "#{arity}Arity"
|
51
|
+
curried_str = curried? ? "#{curried}Curried" : EMPTY_STRING
|
52
|
+
|
53
|
+
"#{arity_str}#{curried_str}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def define_constructor
|
58
|
+
assignment =
|
59
|
+
if curried.equal?(1)
|
60
|
+
'@arg0 = @args[0]'
|
61
|
+
else
|
62
|
+
"#{curried_args.join(', ')} = @args"
|
63
|
+
end
|
64
|
+
|
65
|
+
module_eval(<<~RUBY, __FILE__, __LINE__ + 1)
|
66
|
+
def initialize(*)
|
67
|
+
super
|
68
|
+
|
69
|
+
#{assignment}
|
70
|
+
end
|
71
|
+
RUBY
|
72
|
+
end
|
73
|
+
|
74
|
+
def define_splat_application
|
75
|
+
application =
|
76
|
+
if curried?
|
77
|
+
"@predicate[#{curried_args.join(', ')}, *input]"
|
78
|
+
else
|
79
|
+
'@predicate[*input]'
|
80
|
+
end
|
81
|
+
|
82
|
+
module_eval(<<~RUBY, __FILE__, __LINE__ + 1)
|
83
|
+
def call(*input)
|
84
|
+
if #{application}
|
85
|
+
Result::SUCCESS
|
86
|
+
else
|
87
|
+
Result.new(false, id) { ast(*input) }
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def [](*input)
|
92
|
+
#{application}
|
93
|
+
end
|
94
|
+
RUBY
|
95
|
+
end
|
96
|
+
|
97
|
+
def define_fixed_application
|
98
|
+
parameters = unapplied_args.join(', ')
|
99
|
+
application = "@predicate[#{ (curried_args + unapplied_args).join(', ') }]"
|
100
|
+
|
101
|
+
module_eval(<<~RUBY, __FILE__, __LINE__ + 1)
|
102
|
+
def call(#{parameters})
|
103
|
+
if #{application}
|
104
|
+
Result::SUCCESS
|
105
|
+
else
|
106
|
+
Result.new(false, id) { ast(#{parameters}) }
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def [](#{parameters})
|
111
|
+
#{application}
|
112
|
+
end
|
113
|
+
RUBY
|
114
|
+
end
|
115
|
+
|
116
|
+
def curried_args
|
117
|
+
@curried_args ||= ::Array.new(curried) { |i| "@arg#{i}" }
|
118
|
+
end
|
119
|
+
|
120
|
+
def unapplied_args
|
121
|
+
@unapplied_args ||= ::Array.new(unapplied) { |i| "input#{i}" }
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -52,7 +52,7 @@ module Dry
|
|
52
52
|
|
53
53
|
def visit_predicate(node)
|
54
54
|
name, params = node
|
55
|
-
predicate = Rule::Predicate.
|
55
|
+
predicate = Rule::Predicate.build(predicates[name])
|
56
56
|
|
57
57
|
if params.size > 1
|
58
58
|
args = params.map(&:last).reject { |val| val == Undefined }
|
data/lib/dry/logic/version.rb
CHANGED
@@ -9,7 +9,7 @@ RSpec.describe Result do
|
|
9
9
|
end
|
10
10
|
|
11
11
|
context 'with a predicate' do
|
12
|
-
let(:rule) { Rule::Predicate.
|
12
|
+
let(:rule) { Rule::Predicate.build(gt?, args: [18]) }
|
13
13
|
let(:input) { 17 }
|
14
14
|
let(:output) { 'gt?(18, 17)' }
|
15
15
|
|
@@ -17,7 +17,7 @@ RSpec.describe Result do
|
|
17
17
|
end
|
18
18
|
|
19
19
|
context 'with AND operation' do
|
20
|
-
let(:rule) { Rule::Predicate.
|
20
|
+
let(:rule) { Rule::Predicate.build(array?).and(Rule::Predicate.build(empty?)) }
|
21
21
|
let(:input) { '' }
|
22
22
|
let(:output) { 'array?("") AND empty?("")' }
|
23
23
|
|
@@ -25,7 +25,7 @@ RSpec.describe Result do
|
|
25
25
|
end
|
26
26
|
|
27
27
|
context 'with OR operation' do
|
28
|
-
let(:rule) { Rule::Predicate.
|
28
|
+
let(:rule) { Rule::Predicate.build(array?).or(Rule::Predicate.build(empty?)) }
|
29
29
|
let(:input) { 123 }
|
30
30
|
let(:output) { 'array?(123) OR empty?(123)' }
|
31
31
|
|
@@ -33,7 +33,7 @@ RSpec.describe Result do
|
|
33
33
|
end
|
34
34
|
|
35
35
|
context 'with XOR operation' do
|
36
|
-
let(:rule) { Rule::Predicate.
|
36
|
+
let(:rule) { Rule::Predicate.build(array?).xor(Rule::Predicate.build(empty?)) }
|
37
37
|
let(:input) { [] }
|
38
38
|
let(:output) { 'array?([]) XOR empty?([])' }
|
39
39
|
|
@@ -41,7 +41,7 @@ RSpec.describe Result do
|
|
41
41
|
end
|
42
42
|
|
43
43
|
context 'with THEN operation' do
|
44
|
-
let(:rule) { Rule::Predicate.
|
44
|
+
let(:rule) { Rule::Predicate.build(array?).then(Rule::Predicate.build(empty?)) }
|
45
45
|
let(:input) { [1, 2, 3] }
|
46
46
|
let(:output) { 'empty?([1, 2, 3])' }
|
47
47
|
|
@@ -49,7 +49,7 @@ RSpec.describe Result do
|
|
49
49
|
end
|
50
50
|
|
51
51
|
context 'with NOT operation' do
|
52
|
-
let(:rule) { Operations::Negation.new(Rule::Predicate.
|
52
|
+
let(:rule) { Operations::Negation.new(Rule::Predicate.build(array?)) }
|
53
53
|
let(:input) { 'foo' }
|
54
54
|
let(:output) { 'not(array?("foo"))' }
|
55
55
|
|
data/spec/shared/rule.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
shared_examples_for Dry::Logic::Rule do
|
2
|
-
let(:
|
2
|
+
let(:arity) { 2 }
|
3
|
+
let(:predicate) { double(:predicate, arity: arity, name: predicate_name) }
|
3
4
|
let(:rule_type) { described_class }
|
4
5
|
let(:predicate_name) { :good? }
|
5
6
|
|
6
7
|
describe '#arity' do
|
7
8
|
it 'returns its predicate arity' do
|
8
|
-
rule = rule_type.
|
9
|
+
rule = rule_type.build(predicate)
|
9
10
|
|
10
11
|
expect(rule.arity).to be(2)
|
11
12
|
end
|
@@ -13,15 +14,17 @@ shared_examples_for Dry::Logic::Rule do
|
|
13
14
|
|
14
15
|
describe '#parameters' do
|
15
16
|
it 'returns a list of args with their names' do
|
16
|
-
rule = rule_type.
|
17
|
+
rule = rule_type.build(-> foo, bar { true }, args: [312])
|
17
18
|
|
18
19
|
expect(rule.parameters).to eql([[:req, :foo], [:req, :bar]])
|
19
20
|
end
|
20
21
|
end
|
21
22
|
|
22
23
|
describe '#call' do
|
24
|
+
let(:arity) { 1 }
|
25
|
+
|
23
26
|
it 'returns success for valid input' do
|
24
|
-
rule = rule_type.
|
27
|
+
rule = rule_type.build(predicate)
|
25
28
|
|
26
29
|
expect(predicate).to receive(:[]).with(2).and_return(true)
|
27
30
|
|
@@ -29,7 +32,7 @@ shared_examples_for Dry::Logic::Rule do
|
|
29
32
|
end
|
30
33
|
|
31
34
|
it 'returns failure for invalid input' do
|
32
|
-
rule = rule_type.
|
35
|
+
rule = rule_type.build(predicate)
|
33
36
|
|
34
37
|
expect(predicate).to receive(:[]).with(2).and_return(false)
|
35
38
|
|
@@ -38,8 +41,10 @@ shared_examples_for Dry::Logic::Rule do
|
|
38
41
|
end
|
39
42
|
|
40
43
|
describe '#[]' do
|
44
|
+
let(:arity) { 1 }
|
45
|
+
|
41
46
|
it 'delegates to its predicate' do
|
42
|
-
rule = rule_type.
|
47
|
+
rule = rule_type.build(predicate)
|
43
48
|
|
44
49
|
expect(predicate).to receive(:[]).with(2).and_return(true)
|
45
50
|
expect(rule[2]).to be(true)
|
@@ -48,7 +53,7 @@ shared_examples_for Dry::Logic::Rule do
|
|
48
53
|
|
49
54
|
describe '#curry' do
|
50
55
|
it 'returns a curried rule' do
|
51
|
-
rule = rule_type.
|
56
|
+
rule = rule_type.build(predicate).curry(3)
|
52
57
|
|
53
58
|
expect(predicate).to receive(:[]).with(3, 2).and_return(true)
|
54
59
|
expect(rule.args).to eql([3])
|
@@ -59,7 +64,7 @@ shared_examples_for Dry::Logic::Rule do
|
|
59
64
|
it 'raises argument error when arity does not match' do
|
60
65
|
expect(predicate).to receive(:arity).and_return(2)
|
61
66
|
|
62
|
-
expect { rule_type.
|
67
|
+
expect { rule_type.build(predicate).curry(3, 2, 1) }.to raise_error(
|
63
68
|
ArgumentError, 'wrong number of arguments (3 for 2)'
|
64
69
|
)
|
65
70
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -3,8 +3,8 @@ RSpec.describe Operations::And do
|
|
3
3
|
|
4
4
|
include_context 'predicates'
|
5
5
|
|
6
|
-
let(:left) { Rule::Predicate.
|
7
|
-
let(:right) { Rule::Predicate.
|
6
|
+
let(:left) { Rule::Predicate.build(int?) }
|
7
|
+
let(:right) { Rule::Predicate.build(gt?).curry(18) }
|
8
8
|
|
9
9
|
describe '#call' do
|
10
10
|
it 'calls left and right' do
|
@@ -24,6 +24,10 @@ RSpec.describe Operations::And do
|
|
24
24
|
[:and, [[:predicate, [:int?, [[:input, '18']]]], [:hint, [:predicate, [:gt?, [[:num, 18], [:input, '18']]]]]]]
|
25
25
|
)
|
26
26
|
|
27
|
+
expect(operation.with(hints: false).('18').to_ast).to eql(
|
28
|
+
[:predicate, [:int?, [[:input, '18']]]]
|
29
|
+
)
|
30
|
+
|
27
31
|
expect(operation.(18).to_ast).to eql(
|
28
32
|
[:predicate, [:gt?, [[:num, 18], [:input, 18]]]]
|
29
33
|
)
|
@@ -41,7 +45,7 @@ RSpec.describe Operations::And do
|
|
41
45
|
end
|
42
46
|
|
43
47
|
describe '#and' do
|
44
|
-
let(:other) { Rule::Predicate.
|
48
|
+
let(:other) { Rule::Predicate.build(lt?).curry(30) }
|
45
49
|
|
46
50
|
it 'creates and with the other' do
|
47
51
|
expect(operation.and(other).(31)).to be_failure
|
@@ -49,7 +53,7 @@ RSpec.describe Operations::And do
|
|
49
53
|
end
|
50
54
|
|
51
55
|
describe '#or' do
|
52
|
-
let(:other) { Rule::Predicate.
|
56
|
+
let(:other) { Rule::Predicate.build(lt?).curry(14) }
|
53
57
|
|
54
58
|
it 'creates or with the other' do
|
55
59
|
expect(operation.or(other).(13)).to be_success
|
@@ -1,5 +1,5 @@
|
|
1
1
|
RSpec.describe Operations::Attr do
|
2
|
-
subject(:operation) { Operations::Attr.new(Rule::Predicate.
|
2
|
+
subject(:operation) { Operations::Attr.new(Rule::Predicate.build(str?), name: :name) }
|
3
3
|
|
4
4
|
include_context 'predicates'
|
5
5
|
|
@@ -13,7 +13,7 @@ RSpec.describe Operations::Attr do
|
|
13
13
|
end
|
14
14
|
|
15
15
|
describe '#and' do
|
16
|
-
let(:other) { Operations::Attr.new(Rule::Predicate.
|
16
|
+
let(:other) { Operations::Attr.new(Rule::Predicate.build(min_size?).curry(3), name: :name) }
|
17
17
|
|
18
18
|
it 'returns and where value is passed to the right' do
|
19
19
|
present_and_string = operation.and(other)
|
@@ -4,7 +4,7 @@ RSpec.describe Operations::Check do
|
|
4
4
|
describe '#call' do
|
5
5
|
context 'with 1-level nesting' do
|
6
6
|
subject(:operation) do
|
7
|
-
Operations::Check.new(Rule::Predicate.
|
7
|
+
Operations::Check.new(Rule::Predicate.build(eql?).curry(1), id: :compare, keys: [:num])
|
8
8
|
end
|
9
9
|
|
10
10
|
it 'applies predicate to args extracted from the input' do
|
@@ -15,7 +15,7 @@ RSpec.describe Operations::Check do
|
|
15
15
|
|
16
16
|
context 'with 2-levels nesting' do
|
17
17
|
subject(:operation) do
|
18
|
-
Operations::Check.new(Rule::Predicate.
|
18
|
+
Operations::Check.new(Rule::Predicate.build(eql?), id: :compare, keys: [[:nums, :left], [:nums, :right]])
|
19
19
|
end
|
20
20
|
|
21
21
|
it 'applies predicate to args extracted from the input' do
|
@@ -37,7 +37,7 @@ RSpec.describe Operations::Check do
|
|
37
37
|
|
38
38
|
describe '#to_ast' do
|
39
39
|
subject(:operation) do
|
40
|
-
Operations::Check.new(Rule::Predicate.
|
40
|
+
Operations::Check.new(Rule::Predicate.build(str?), keys: [:email])
|
41
41
|
end
|
42
42
|
|
43
43
|
it 'returns ast' do
|
@@ -3,8 +3,8 @@ RSpec.describe Operations::Implication do
|
|
3
3
|
|
4
4
|
include_context 'predicates'
|
5
5
|
|
6
|
-
let(:left) { Rule::Predicate.
|
7
|
-
let(:right) { Rule::Predicate.
|
6
|
+
let(:left) { Rule::Predicate.build(int?) }
|
7
|
+
let(:right) { Rule::Predicate.build(gt?).curry(18) }
|
8
8
|
|
9
9
|
describe '#call' do
|
10
10
|
it 'calls left and right' do
|
@@ -4,7 +4,7 @@ RSpec.describe Operations::Key do
|
|
4
4
|
include_context 'predicates'
|
5
5
|
|
6
6
|
let(:predicate) do
|
7
|
-
Rule::Predicate.
|
7
|
+
Rule::Predicate.build(key?).curry(:age)
|
8
8
|
end
|
9
9
|
|
10
10
|
describe '#call' do
|
@@ -32,7 +32,7 @@ RSpec.describe Operations::Key do
|
|
32
32
|
end
|
33
33
|
|
34
34
|
let(:predicate) do
|
35
|
-
Operations::Set.new(Rule::Predicate.
|
35
|
+
Operations::Set.new(Rule::Predicate.build(key?).curry(:city), Rule::Predicate.build(key?).curry(:zipcode))
|
36
36
|
end
|
37
37
|
|
38
38
|
it 'applies set rule to the value that passes' do
|
@@ -60,7 +60,7 @@ RSpec.describe Operations::Key do
|
|
60
60
|
end
|
61
61
|
|
62
62
|
let(:predicate) do
|
63
|
-
Operations::Each.new(Rule::Predicate.
|
63
|
+
Operations::Each.new(Rule::Predicate.build(str?))
|
64
64
|
end
|
65
65
|
|
66
66
|
it 'applies each rule to the value that passses' do
|
@@ -108,11 +108,11 @@ RSpec.describe Operations::Key do
|
|
108
108
|
|
109
109
|
describe '#and' do
|
110
110
|
subject(:operation) do
|
111
|
-
Operations::Key.new(Rule::Predicate.
|
111
|
+
Operations::Key.new(Rule::Predicate.build(str?), name: [:user, :name])
|
112
112
|
end
|
113
113
|
|
114
114
|
let(:other) do
|
115
|
-
Operations::Key.new(Rule::Predicate.
|
115
|
+
Operations::Key.new(Rule::Predicate.build(filled?), name: [:user, :name])
|
116
116
|
end
|
117
117
|
|
118
118
|
it 'returns and rule where value is passed to the right' do
|
@@ -3,11 +3,11 @@ RSpec.describe Operations::Or do
|
|
3
3
|
|
4
4
|
include_context 'predicates'
|
5
5
|
|
6
|
-
let(:left) { Rule::Predicate.
|
7
|
-
let(:right) { Rule::Predicate.
|
6
|
+
let(:left) { Rule::Predicate.build(nil?) }
|
7
|
+
let(:right) { Rule::Predicate.build(gt?).curry(18) }
|
8
8
|
|
9
9
|
let(:other) do
|
10
|
-
Rule::Predicate.
|
10
|
+
Rule::Predicate.build(int?) & Rule::Predicate.build(lt?).curry(14)
|
11
11
|
end
|
12
12
|
|
13
13
|
describe '#call' do
|
@@ -3,8 +3,8 @@ RSpec.describe Operations::Set do
|
|
3
3
|
|
4
4
|
include_context 'predicates'
|
5
5
|
|
6
|
-
let(:is_int) { Rule::Predicate.
|
7
|
-
let(:gt_18) { Rule::Predicate.
|
6
|
+
let(:is_int) { Rule::Predicate.build(int?) }
|
7
|
+
let(:gt_18) { Rule::Predicate.build(gt?, args: [18]) }
|
8
8
|
|
9
9
|
describe '#call' do
|
10
10
|
it 'applies all its rules to the input' do
|
@@ -3,11 +3,11 @@ RSpec.describe Operations::Xor do
|
|
3
3
|
|
4
4
|
include_context 'predicates'
|
5
5
|
|
6
|
-
let(:left) { Rule::Predicate.
|
7
|
-
let(:right) { Rule::Predicate.
|
6
|
+
let(:left) { Rule::Predicate.build(array?) }
|
7
|
+
let(:right) { Rule::Predicate.build(empty?) }
|
8
8
|
|
9
9
|
let(:other) do
|
10
|
-
Rule::Predicate.
|
10
|
+
Rule::Predicate.build(str?)
|
11
11
|
end
|
12
12
|
|
13
13
|
describe '#call' do
|
@@ -1,5 +1,5 @@
|
|
1
1
|
RSpec.describe Rule::Predicate do
|
2
|
-
subject(:rule) { Rule::Predicate.
|
2
|
+
subject(:rule) { Rule::Predicate.build(predicate) }
|
3
3
|
|
4
4
|
let(:predicate) { str? }
|
5
5
|
|
@@ -27,11 +27,11 @@ RSpec.describe Rule::Predicate do
|
|
27
27
|
end
|
28
28
|
|
29
29
|
context 'with a result' do
|
30
|
-
it 'returns success
|
31
|
-
expect(rule.('foo')
|
30
|
+
it 'returns success' do
|
31
|
+
expect(rule.('foo')).to be_success
|
32
32
|
end
|
33
33
|
|
34
|
-
it 'returns ast' do
|
34
|
+
it 'returns failure ast' do
|
35
35
|
expect(rule.(5).to_ast).to eql([:predicate, [:str?, [[:input, 5]]]])
|
36
36
|
end
|
37
37
|
end
|
@@ -13,7 +13,7 @@ RSpec.describe Dry::Logic::RuleCompiler, '#call' do
|
|
13
13
|
|
14
14
|
let(:predicate) { double(:predicate, name: :test?, arity: 2).as_null_object }
|
15
15
|
|
16
|
-
let(:rule) { Rule::Predicate.
|
16
|
+
let(:rule) { Rule::Predicate.build(predicate) }
|
17
17
|
let(:key_op) { Operations::Key.new(rule, name: :email) }
|
18
18
|
let(:attr_op) { Operations::Attr.new(rule, name: :email) }
|
19
19
|
let(:check_op) { Operations::Check.new(rule, keys: [:email]) }
|
data/spec/unit/rule_spec.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
RSpec.describe Dry::Logic::Rule do
|
2
|
-
subject(:rule) { Rule.
|
2
|
+
subject(:rule) { Rule.build(predicate, options) }
|
3
3
|
|
4
4
|
let(:predicate) { -> { true } }
|
5
5
|
let(:options) { {} }
|
6
6
|
|
7
7
|
let(:schema) do
|
8
|
-
Class.new
|
8
|
+
Class.new do
|
9
9
|
define_method(:class, Kernel.instance_method(:class))
|
10
10
|
|
11
11
|
def method_missing(m, *)
|
@@ -34,29 +34,29 @@ RSpec.describe Dry::Logic::Rule do
|
|
34
34
|
|
35
35
|
describe '.new' do
|
36
36
|
it 'accepts an :id' do
|
37
|
-
expect(Rule.
|
37
|
+
expect(Rule.build(predicate, id: :check_num).id).to be(:check_num)
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
41
|
describe 'with a function returning truthy value' do
|
42
42
|
it 'is successful for valid input' do
|
43
|
-
expect(Rule.
|
43
|
+
expect(Rule.build(-> val { val }).('true')).to be_success
|
44
44
|
end
|
45
45
|
|
46
46
|
it 'is not successful for invalid input' do
|
47
|
-
expect(Rule.
|
47
|
+
expect(Rule.build(-> val { val }).(nil)).to be_failure
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
51
|
describe '#ast' do
|
52
52
|
it 'returns predicate node with :id' do
|
53
|
-
expect(Rule.
|
53
|
+
expect(Rule.build(-> value { true }).with(id: :email?).ast('oops')).to eql(
|
54
54
|
[:predicate, [:email?, [[:value, 'oops']]]]
|
55
55
|
)
|
56
56
|
end
|
57
57
|
|
58
58
|
it 'returns predicate node with undefined args' do
|
59
|
-
expect(Rule.
|
59
|
+
expect(Rule.build(-> value { true }).with(id: :email?).ast).to eql(
|
60
60
|
[:predicate, [:email?, [[:value, Undefined]]]]
|
61
61
|
)
|
62
62
|
end
|
@@ -120,7 +120,7 @@ RSpec.describe Dry::Logic::Rule do
|
|
120
120
|
|
121
121
|
describe '#eval_args' do
|
122
122
|
context 'with an unbound method' do
|
123
|
-
let(:options) { { args: [1, klass.instance_method(:num), :foo] } }
|
123
|
+
let(:options) { { args: [1, klass.instance_method(:num), :foo], arity: 3 } }
|
124
124
|
let(:klass) { Class.new { def num; 7; end } }
|
125
125
|
let(:object) { klass.new }
|
126
126
|
|
@@ -130,7 +130,7 @@ RSpec.describe Dry::Logic::Rule do
|
|
130
130
|
end
|
131
131
|
|
132
132
|
context 'with a schema instance' do
|
133
|
-
let(:options) { { args: [1, schema, :foo] } }
|
133
|
+
let(:options) { { args: [1, schema, :foo], arity: 3 } }
|
134
134
|
let(:object) { Object.new }
|
135
135
|
|
136
136
|
it 'returns a new with its predicate executed in the context of the provided object' do
|
@@ -138,4 +138,65 @@ RSpec.describe Dry::Logic::Rule do
|
|
138
138
|
end
|
139
139
|
end
|
140
140
|
end
|
141
|
+
|
142
|
+
describe 'arity specialization' do
|
143
|
+
describe '0-arity rule' do
|
144
|
+
let(:options) { { args: [1], arity: 1 } }
|
145
|
+
let(:predicate) { :odd?.to_proc }
|
146
|
+
|
147
|
+
it 'generates interface with the right arity' do
|
148
|
+
expect(rule.method(:call).arity).to be_zero
|
149
|
+
expect(rule.method(:[]).arity).to be_zero
|
150
|
+
expect(rule[]).to be(true)
|
151
|
+
expect(rule.()).to be_success
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
describe '1-arity rule' do
|
156
|
+
let(:options) { { args: [1], arity: 2 } }
|
157
|
+
let(:predicate) { -> a, b { a + b } }
|
158
|
+
|
159
|
+
it 'generates interface with the right arity' do
|
160
|
+
expect(rule.method(:call).arity).to be(1)
|
161
|
+
expect(rule.method(:[]).arity).to be(1)
|
162
|
+
expect(rule[10]).to be(11)
|
163
|
+
expect(rule.(1)).to be_success
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
describe 'currying' do
|
168
|
+
let(:options) { { args: [], arity: 2 } }
|
169
|
+
let(:predicate) { -> a, b { a + b } }
|
170
|
+
let(:rule) { super().curry(1) }
|
171
|
+
|
172
|
+
it 'generates correct arity on currying' do
|
173
|
+
expect(rule.method(:call).arity).to be(1)
|
174
|
+
expect(rule.method(:[]).arity).to be(1)
|
175
|
+
expect(rule[10]).to be(11)
|
176
|
+
expect(rule.(1)).to be_success
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
describe 'arbitrary arity' do
|
181
|
+
let(:arity) { rand(20) }
|
182
|
+
let(:curried) { arity.zero? ? 0 : rand(arity) }
|
183
|
+
|
184
|
+
let(:options) { { args: [1] * curried, arity: arity } }
|
185
|
+
let(:predicate) { double(:predicate) }
|
186
|
+
|
187
|
+
it 'generates correct arity' do
|
188
|
+
expect(rule.method(:call).arity).to be(arity - curried)
|
189
|
+
expect(rule.method(:[]).arity).to be(arity - curried)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
describe '-1 arity' do
|
194
|
+
let(:options) { { args: [], arity: -1 } }
|
195
|
+
|
196
|
+
it 'accepts variable number of arguments' do
|
197
|
+
expect(rule.method(:call).arity).to be(-1)
|
198
|
+
expect(rule.method(:[]).arity).to be(-1)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
141
202
|
end
|
metadata
CHANGED
@@ -1,39 +1,36 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dry-logic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Solnica
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-04-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: concurrent-ruby
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0
|
19
|
+
version: '1.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0
|
26
|
+
version: '1.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name: dry-
|
28
|
+
name: dry-core
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0.2'
|
34
|
-
- - ">="
|
35
|
-
- !ruby/object:Gem::Version
|
36
|
-
version: 0.2.6
|
37
34
|
type: :runtime
|
38
35
|
prerelease: false
|
39
36
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -41,9 +38,6 @@ dependencies:
|
|
41
38
|
- - "~>"
|
42
39
|
- !ruby/object:Gem::Version
|
43
40
|
version: '0.2'
|
44
|
-
- - ">="
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
version: 0.2.6
|
47
41
|
- !ruby/object:Gem::Dependency
|
48
42
|
name: dry-equalizer
|
49
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -110,8 +104,6 @@ files:
|
|
110
104
|
- ".codeclimate.yml"
|
111
105
|
- ".gitignore"
|
112
106
|
- ".rspec"
|
113
|
-
- ".rubocop.yml"
|
114
|
-
- ".rubocop_todo.yml"
|
115
107
|
- ".travis.yml"
|
116
108
|
- CHANGELOG.md
|
117
109
|
- CONTRIBUTING.md
|
@@ -119,6 +111,8 @@ files:
|
|
119
111
|
- LICENSE
|
120
112
|
- README.md
|
121
113
|
- Rakefile
|
114
|
+
- benchmarks/rule_application.rb
|
115
|
+
- benchmarks/setup.rb
|
122
116
|
- bin/console
|
123
117
|
- dry-logic.gemspec
|
124
118
|
- examples/basic.rb
|
@@ -144,6 +138,7 @@ files:
|
|
144
138
|
- lib/dry/logic/predicates.rb
|
145
139
|
- lib/dry/logic/result.rb
|
146
140
|
- lib/dry/logic/rule.rb
|
141
|
+
- lib/dry/logic/rule/interface.rb
|
147
142
|
- lib/dry/logic/rule/predicate.rb
|
148
143
|
- lib/dry/logic/rule_compiler.rb
|
149
144
|
- lib/dry/logic/version.rb
|
@@ -221,7 +216,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
221
216
|
- !ruby/object:Gem::Version
|
222
217
|
version: '0'
|
223
218
|
requirements: []
|
224
|
-
rubygems_version: 3.0.
|
219
|
+
rubygems_version: 3.0.3
|
225
220
|
signing_key:
|
226
221
|
specification_version: 4
|
227
222
|
summary: Predicate logic with rule composition
|
data/.rubocop.yml
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
# Generated by `rubocop --auto-gen-config`
|
2
|
-
inherit_from: .rubocop_todo.yml
|
3
|
-
|
4
|
-
Metrics/LineLength:
|
5
|
-
Max: 100
|
6
|
-
|
7
|
-
Style/Documentation:
|
8
|
-
Enabled: false
|
9
|
-
|
10
|
-
Lint/HandleExceptions:
|
11
|
-
Exclude:
|
12
|
-
- rakelib/*.rake
|
13
|
-
|
14
|
-
Style/FileName:
|
15
|
-
Exclude:
|
16
|
-
- lib/dry-logic.rb
|
data/.rubocop_todo.yml
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
# This configuration was generated by
|
2
|
-
# `rubocop --auto-gen-config`
|
3
|
-
# on 2015-10-30 01:32:46 +0000 using RuboCop version 0.34.2.
|
4
|
-
# The point is for the user to remove these configuration records
|
5
|
-
# one by one as the offenses are removed from the code base.
|
6
|
-
# Note that changes in the inspected code, or installation of new
|
7
|
-
# versions of RuboCop, may require this file to be generated again.
|