dry-logic 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 [![Join the chat at https://dry-rb.zulipchat.com](https://img.shields.io/badge/dry--rb-join%20chat-%23346b7a.svg)][chat]
|
8
8
|
|
9
9
|
[![Gem Version](https://badge.fury.io/rb/dry-logic.svg)][gem]
|
10
10
|
[![Build Status](https://travis-ci.org/dry-rb/dry-logic.svg?branch=master)][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.
|