dry-logic 0.4.1 → 0.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 8706db20bc46c7c3b7f20fe03bfbc0068e9be304
4
- data.tar.gz: 6b07fca8b0cdccdbf87e7cd2d0287f04383ab155
2
+ SHA256:
3
+ metadata.gz: 1a6ff887f61b513496991a96d7903685886ab29dae71cb4f75185cd7866fd4b2
4
+ data.tar.gz: 9e063f346341b395ac21645f84319e619af19151e62bd97413badf246440d353
5
5
  SHA512:
6
- metadata.gz: 4b563117d6c9ecc31d37e3be476064f020b640b6208087a658cb329b0186ace8de62d7a5795a0c8578890ff131c2859fd0cc934a2c9080f6f1024daa1db6c988
7
- data.tar.gz: 78f7d1b67309c6df1a4b027b32f5200c74daa676d8fa76ab7086f5a84ff91cb8e970623805eca85ff150e6f9ac0a01a43244e26e57aadd0fe3546927bdafef9d
6
+ metadata.gz: f643a0238e3b67c91c83af1e90cb4398279b4c01957ce663a5186ae8437a87e94c9d9cb2f7a2aabca1c7edb47be28a531317a044e58e270ffff59c44e6a9ccf5
7
+ data.tar.gz: 17b0ff20fc5c41258a537ad0c57e959cd3359765801261157772a62ee5d1ce525c15bca2ce92c8ee624b1fda67a5cf6cbf4228af552cf99efc8e8428026dbccb
data/.gitignore CHANGED
@@ -2,7 +2,6 @@
2
2
  coverage
3
3
  /.bundle
4
4
  vendor/bundle
5
- bin/
6
5
  tmp/
7
6
  .idea/
8
7
  Gemfile.lock
@@ -1,36 +1,30 @@
1
1
  language: ruby
2
- dist: trusty
3
- sudo: false
4
2
  cache: bundler
5
- bundler_args: --without console tools
3
+ sudo: false
4
+ bundler_args: --without benchmarks tools
5
+ before_install: gem update --system
6
+ before_script:
7
+ - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
8
+ - chmod +x ./cc-test-reporter
9
+ - ./cc-test-reporter before-build
10
+ after_script:
11
+ - "[ -d coverage ] && ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT"
6
12
  script:
7
- - bundle exec rake spec
8
- before_install:
9
- - gem update --system
10
- - rvm @global do gem uninstall bundler -a -x
11
- - rvm @global do gem install bundler -v 1.13.7
12
- after_success:
13
- # Send coverage report from the job #1 == current MRI release
14
- - '[ "${TRAVIS_JOB_NUMBER#*.}" = "1" ] && [ "$TRAVIS_BRANCH" = "master" ] && bundle exec codeclimate-test-reporter'
13
+ - bundle exec rake
15
14
  rvm:
16
- - 2.3
17
- - 2.2
18
- - 2.1
19
- - jruby-9.1.5.0
20
- - ruby-head
21
- - rbx-3
15
+ - 2.6.0
16
+ - 2.5.3
17
+ - 2.4.5
18
+ - 2.3.8
19
+ - jruby-9.2.5.0
22
20
  env:
23
21
  global:
24
- - JRUBY_OPTS='--dev -J-Xmx1024M'
25
- matrix:
26
- allow_failures:
27
- - rvm: ruby-head
28
- - rvm: rbx-3
22
+ - COVERAGE=true
29
23
  notifications:
30
24
  email: false
31
25
  webhooks:
32
26
  urls:
33
27
  - https://webhooks.gitter.im/e/19098b4253a72c9796db
34
- on_success: change # options: [always|never|change] default: always
35
- on_failure: always # options: [always|never|change] default: always
36
- on_start: false # default: false
28
+ on_success: change # options: [always|never|change] default: always
29
+ on_failure: always # options: [always|never|change] default: always
30
+ on_start: false # default: false
@@ -1,14 +1,39 @@
1
+ # v0.5.0 2019-01-29
2
+
3
+ ### Added
4
+
5
+ - `:nil?` predicate (`none?` is now an alias) (solnic)
6
+
7
+ ### Fixed
8
+
9
+ - `Operation::Key#ast` will now return a correct AST with non-Undefined inputs (solnic)
10
+
11
+ [Compare v0.4.2...v0.5.0](https://github.com/dry-rb/dry-logic/compare/v0.4.2...v0.5.0)
12
+
13
+ # v0.4.2 2017-09-15
14
+
15
+ ### Added
16
+
17
+ - New `:case?` predicate matches a value against the given object with `#===` (flash-gordon)
18
+ - New `:is?` predicate checks objects identity (using `#equal?`) (flash-gordon)
19
+
20
+ ### Fixed
21
+
22
+ - A bug with using custom predicates within a standalone module in `dry-validation` (flash-gordon)
23
+
24
+ [Compare v0.4.1...v0.4.2](https://github.com/dry-rb/dry-logic/compare/v0.4.1...v0.4.2)
25
+
1
26
  # v0.4.1 2017-01-23
2
27
 
3
28
  ### Changed
4
29
 
5
- * Predicates simply reuse other predicate methods instead of referring to them via `#[]` (georgemillo)
30
+ - Predicates simply reuse other predicate methods instead of referring to them via `#[]` (georgemillo)
6
31
 
7
32
  ### Fixed
8
33
 
9
- * Warnings on MRI 2.4.0 are gone (jtippett)
34
+ - Warnings on MRI 2.4.0 are gone (jtippett)
10
35
 
11
- [Compare v0.4.0...v0.4.1](https://github.com/dryrb/dry-logic/compare/v0.4.0...v0.4.1)
36
+ [Compare v0.4.0...v0.4.1](https://github.com/dry-rb/dry-logic/compare/v0.4.0...v0.4.1)
12
37
 
13
38
  # v0.4.0 2016-09-21
14
39
 
@@ -16,116 +41,116 @@ This is a partial rewrite focused on internal clean up and major performance imp
16
41
 
17
42
  ### Added
18
43
 
19
- * `Rule#[]` which applies a rule and always returns `true` or `false` (solnic)
20
- * `Rule#bind` which returns a rule with its predicate bound to a given object (solnic)
21
- * `Rule#eval_args` which evaluates unbound-methods-args in the context of a given object (solnic)
22
- * `Logic.Rule` builder function (solnic)
23
- * Nice `#inspect` on rules and operation objects (solnic)
44
+ - `Rule#[]` which applies a rule and always returns `true` or `false` (solnic)
45
+ - `Rule#bind` which returns a rule with its predicate bound to a given object (solnic)
46
+ - `Rule#eval_args` which evaluates unbound-methods-args in the context of a given object (solnic)
47
+ - `Logic.Rule` builder function (solnic)
48
+ - Nice `#inspect` on rules and operation objects (solnic)
24
49
 
25
50
  ### Changed
26
51
 
27
- * [BRAEKING] New result API (solnic)
28
- * [BREAKING] `Predicate` is now `Rule::Predicate` (solnic)
29
- * [BREAKING] `Rule::Conjunction` is now `Operation::And` (solnic)
30
- * [BREAKING] `Rule::Disjunction` is now `Operation::Or` (solnic)
31
- * [BREAKING] `Rule::ExlusiveDisjunction` is now `Operation::Xor` (solnic)
32
- * [BREAKING] `Rule::Implication` is now `Operation::Implication` (solnic)
33
- * [BREAKING] `Rule::Set` is now `Operation::Set` (solnic)
34
- * [BREAKING] `Rule::Each` is now `Operation::Each` (solnic)
35
- * [BREAKING] `Rule.new` accepts a predicate function as its first arg now (solnic)
36
- * [BREAKING] `Rule#name` is now `Rule#id` (solnic)
37
- * `Rule#parameters` is public now (solnic)
52
+ - [BRAEKING] New result API (solnic)
53
+ - [BREAKING] `Predicate` is now `Rule::Predicate` (solnic)
54
+ - [BREAKING] `Rule::Conjunction` is now `Operation::And` (solnic)
55
+ - [BREAKING] `Rule::Disjunction` is now `Operation::Or` (solnic)
56
+ - [BREAKING] `Rule::ExlusiveDisjunction` is now `Operation::Xor` (solnic)
57
+ - [BREAKING] `Rule::Implication` is now `Operation::Implication` (solnic)
58
+ - [BREAKING] `Rule::Set` is now `Operation::Set` (solnic)
59
+ - [BREAKING] `Rule::Each` is now `Operation::Each` (solnic)
60
+ - [BREAKING] `Rule.new` accepts a predicate function as its first arg now (solnic)
61
+ - [BREAKING] `Rule#name` is now `Rule#id` (solnic)
62
+ - `Rule#parameters` is public now (solnic)
38
63
 
39
- [Compare v0.3.0...v0.4.0](https://github.com/dryrb/dry-logic/compare/v0.3.0...v0.4.0)
64
+ [Compare v0.3.0...v0.4.0](https://github.com/dry-rb/dry-logic/compare/v0.3.0...v0.4.0)
40
65
 
41
66
  # v0.3.0 2016-07-01
42
67
 
43
68
  ### Added
44
69
 
45
- * `:type?` predicate imported from dry-types (solnic)
46
- * `Rule#curry` interface (solnic)
70
+ - `:type?` predicate imported from dry-types (solnic)
71
+ - `Rule#curry` interface (solnic)
47
72
 
48
73
  ### Changed
49
74
 
50
- * Predicates AST now includes information about args (names & possible values) (fran-worley + solnic)
51
- * Predicates raise errors when they are called with invalid arity (fran-worley + solnic)
52
- * Rules no longer evaluate input twice when building result objects (solnic)
75
+ - Predicates AST now includes information about args (names & possible values) (fran-worley + solnic)
76
+ - Predicates raise errors when they are called with invalid arity (fran-worley + solnic)
77
+ - Rules no longer evaluate input twice when building result objects (solnic)
53
78
 
54
- [Compare v0.2.3...v0.3.0](https://github.com/dryrb/dry-logic/compare/v0.2.3...v0.3.0)
79
+ [Compare v0.2.3...v0.3.0](https://github.com/dry-rb/dry-logic/compare/v0.2.3...v0.3.0)
55
80
 
56
81
  # v0.2.3 2016-05-11
57
82
 
58
83
  ### Added
59
84
 
60
- * `not_eql?`, `includes?`, `excludes?` predicates (fran-worley)
85
+ - `not_eql?`, `includes?`, `excludes?` predicates (fran-worley)
61
86
 
62
87
  ### Changed
63
88
 
64
- * Renamed `inclusion?` to `included_in?` and deprecated `inclusion?` (fran-worley)
65
- * Renamed `exclusion?` to `excluded_from?` and deprecated `exclusion?` (fran-worley)
89
+ - Renamed `inclusion?` to `included_in?` and deprecated `inclusion?` (fran-worley)
90
+ - Renamed `exclusion?` to `excluded_from?` and deprecated `exclusion?` (fran-worley)
66
91
 
67
- [Compare v0.2.2...v0.2.3](https://github.com/dryrb/dry-logic/compare/v0.2.2...v0.2.3)
92
+ [Compare v0.2.2...v0.2.3](https://github.com/dry-rb/dry-logic/compare/v0.2.2...v0.2.3)
68
93
 
69
94
  # v0.2.2 2016-03-30
70
95
 
71
96
  ### Added
72
97
 
73
- * `number?`, `odd?`, `even?` predicates (fran-worley)
98
+ - `number?`, `odd?`, `even?` predicates (fran-worley)
74
99
 
75
- [Compare v0.2.1...v0.2.2](https://github.com/dryrb/dry-logic/compare/v0.2.1...v0.2.2)
100
+ [Compare v0.2.1...v0.2.2](https://github.com/dry-rb/dry-logic/compare/v0.2.1...v0.2.2)
76
101
 
77
102
  # v0.2.1 2016-03-20
78
103
 
79
104
  ### Fixed
80
105
 
81
- * Result AST for `Rule::Each` correctly maps elements with eql inputs (solnic)
106
+ - Result AST for `Rule::Each` correctly maps elements with eql inputs (solnic)
82
107
 
83
108
  # v0.2.0 2016-03-11
84
109
 
85
110
  ### Changed
86
111
 
87
- * Entire AST has been redefined (solnic)
112
+ - Entire AST has been redefined (solnic)
88
113
 
89
- [Compare v0.1.4...v0.2.0](https://github.com/dryrb/dry-logic/compare/v0.1.4...v0.2.0)
114
+ [Compare v0.1.4...v0.2.0](https://github.com/dry-rb/dry-logic/compare/v0.1.4...v0.2.0)
90
115
 
91
116
  # v0.1.4 2016-01-27
92
117
 
93
118
  ### Added
94
119
 
95
- * Support for hash-names in `Check` and `Result` which can properly resolve input
120
+ - Support for hash-names in `Check` and `Result` which can properly resolve input
96
121
  from nested results (solnic)
97
122
 
98
- [Compare v0.1.3...v0.1.4](https://github.com/dryrb/dry-logic/compare/v0.1.3...v0.1.4)
123
+ [Compare v0.1.3...v0.1.4](https://github.com/dry-rb/dry-logic/compare/v0.1.3...v0.1.4)
99
124
 
100
125
  # v0.1.3 2016-01-27
101
126
 
102
127
  ### Added
103
128
 
104
- * Support for resolving input from `Rule::Result` (solnic)
129
+ - Support for resolving input from `Rule::Result` (solnic)
105
130
 
106
131
  ### Changed
107
132
 
108
- * `Check` and `Result` carry original input(s) (solnic)
133
+ - `Check` and `Result` carry original input(s) (solnic)
109
134
 
110
- [Compare v0.1.2...v0.1.3](https://github.com/dryrb/dry-logic/compare/v0.1.2...v0.1.3)
135
+ [Compare v0.1.2...v0.1.3](https://github.com/dry-rb/dry-logic/compare/v0.1.2...v0.1.3)
111
136
 
112
137
  # v0.1.2 2016-01-19
113
138
 
114
139
  ### Fixed
115
140
 
116
- * `xor` returns wrapped results when used against another result-rule (solnic)
141
+ - `xor` returns wrapped results when used against another result-rule (solnic)
117
142
 
118
- [Compare v0.1.1...v0.1.2](https://github.com/dryrb/dry-logic/compare/v0.1.1...v0.1.2)
143
+ [Compare v0.1.1...v0.1.2](https://github.com/dry-rb/dry-logic/compare/v0.1.1...v0.1.2)
119
144
 
120
145
  # v0.1.1 2016-01-18
121
146
 
122
147
  ### Added
123
148
 
124
- * `Rule::Attr` which can be applied to a data object with attr readers (SunnyMagadan)
125
- * `Rule::Result` which can be applied to a result object (solnic)
126
- * `true?` and `false?` predicates (solnic)
149
+ - `Rule::Attr` which can be applied to a data object with attr readers (SunnyMagadan)
150
+ - `Rule::Result` which can be applied to a result object (solnic)
151
+ - `true?` and `false?` predicates (solnic)
127
152
 
128
- [Compare v0.1.0...v0.1.1](https://github.com/dryrb/dry-logic/compare/v0.1.0...v0.1.1)
153
+ [Compare v0.1.0...v0.1.1](https://github.com/dry-rb/dry-logic/compare/v0.1.0...v0.1.1)
129
154
 
130
155
  # v0.1.0 2016-01-11
131
156
 
@@ -0,0 +1,29 @@
1
+ # Issue Guidelines
2
+
3
+ ## Reporting bugs
4
+
5
+ If you found a bug, report an issue and describe what's the expected behavior versus what actually happens. If the bug causes a crash, attach a full backtrace. If possible, a reproduction script showing the problem is highly appreciated.
6
+
7
+ ## Reporting feature requests
8
+
9
+ Report a feature request **only after discussing it first on [discuss.dry-rb.org](https://discuss.dry-rb.org)** where it was accepted. Please provide a concise description of the feature, don't link to a discussion thread, and instead summarize what was discussed.
10
+
11
+ ## Reporting questions, support requests, ideas, concerns etc.
12
+
13
+ **PLEASE DON'T** - use [discuss.dry-rb.org](http://discuss.dry-rb.org) instead.
14
+
15
+ # Pull Request Guidelines
16
+
17
+ A Pull Request will only be accepted if it addresses a specific issue that was reported previously, or fixes typos, mistakes in documentation etc.
18
+
19
+ Other requirements:
20
+
21
+ 1) Do not open a pull request if you can't provide tests along with it. If you have problems writing tests, ask for help in the related issue.
22
+ 2) Follow the style conventions of the surrounding code. In most cases, this is standard ruby style.
23
+ 3) Add API documentation if it's a new feature
24
+ 4) Update API documentation if it changes an existing feature
25
+ 5) Bonus points for sending a PR to [github.com/dry-rb/dry-rb.org](github.com/dry-rb/dry-rb.org) which updates user documentation and guides
26
+
27
+ # Asking for help
28
+
29
+ If these guidelines aren't helpful, and you're stuck, please post a message on [discuss.dry-rb.org](https://discuss.dry-rb.org).
data/Gemfile CHANGED
@@ -3,7 +3,6 @@ source 'https://rubygems.org'
3
3
  gemspec
4
4
 
5
5
  group :test do
6
- gem 'codeclimate-test-reporter', platform: :mri
7
6
  gem 'simplecov', require: false, platform: :mri
8
7
  end
9
8
 
data/README.md CHANGED
@@ -1,6 +1,5 @@
1
1
  [gem]: https://rubygems.org/gems/dry-logic
2
2
  [travis]: https://travis-ci.org/dry-rb/dry-logic
3
- [gemnasium]: https://gemnasium.com/dry-rb/dry-logic
4
3
  [codeclimate]: https://codeclimate.com/github/dry-rb/dry-logic
5
4
  [coveralls]: https://coveralls.io/r/dry-rb/dry-logic
6
5
  [inchpages]: http://inch-ci.org/github/dry-rb/dry-logic
@@ -9,7 +8,6 @@
9
8
 
10
9
  [![Gem Version](https://badge.fury.io/rb/dry-logic.svg)][gem]
11
10
  [![Build Status](https://travis-ci.org/dry-rb/dry-logic.svg?branch=master)][travis]
12
- [![Dependency Status](https://gemnasium.com/dry-rb/dry-logic.svg)][gemnasium]
13
11
  [![Code Climate](https://codeclimate.com/github/dry-rb/dry-logic/badges/gpa.svg)][codeclimate]
14
12
  [![Test Coverage](https://codeclimate.com/github/dry-rb/dry-logic/badges/coverage.svg)][codeclimate]
15
13
  [![Inline docs](http://inch-ci.org/github/dry-rb/dry-logic.svg?branch=master)][inchpages]
@@ -20,36 +18,13 @@ Predicate logic and rule composition used by:
20
18
  * [dry-validation](https://github.com/dry-rb/dry-validation) for composing validation rules
21
19
  * your project...?
22
20
 
23
- ## Synopsis
21
+ ## Links
24
22
 
25
- ``` ruby
26
- require 'dry/logic'
27
- require 'dry/logic/predicates'
23
+ * [Documentation](http://dry-rb.org/gems/dry-logic)
28
24
 
29
- include Dry::Logic
25
+ ## Contributing
30
26
 
31
- user_present = Rule::Key.new(Predicates[:filled?], name: :user)
32
-
33
- has_min_age = Rule::Key.new(Predicates[:int?], name: [:user, :age])
34
- & Rule::Key.new(Predicates[:gt?].curry(18), name: [:user, :age])
35
-
36
- user_rule = user_present & has_min_age
37
-
38
- user_rule.(user: { age: 19 })
39
- # #<Dry::Logic::Result::Named success?=true input={:user=>{:age=>19}} rule=#<Dry::Logic::Rule::Key predicate=#<Dry::Logic::Predicate id=:gt? args=[18, 19]> options={:evaluator=>#<Dry::Logic::Evaluator::Key path=[:user, :age]>, :name=>[:user, :age]}>>
40
-
41
- user_rule.(user: { age: 18 })
42
- # #<Dry::Logic::Result::Named success?=false input={:user=>{:age=>18}} rule=#<Dry::Logic::Rule::Key predicate=#<Dry::Logic::Predicate id=:gt? args=[18, 18]> options={:evaluator=>#<Dry::Logic::Evaluator::Key path=[:user, :age]>, :name=>[:user, :age]}>>
43
-
44
- user_rule.(user: { age: 'seventeen' }).inspect
45
- #<Dry::Logic::Result::Named success?=false input={:user=>{:age=>"seventeen"}} rule=#<Dry::Logic::Rule::Key predicate=#<Dry::Logic::Predicate id=:int? args=["seventeen"]> options={:evaluator=>#<Dry::Logic::Evaluator::Key path=[:user, :age]>, :name=>[:user, :age]}>>
46
-
47
- user_rule.(user: { }).inspect
48
- #<Dry::Logic::Result::Named success?=false input={:user=>{}} rule=#<Dry::Logic::Rule::Key predicate=#<Dry::Logic::Predicate id=:filled? args=[{}]> options={:evaluator=>#<Dry::Logic::Evaluator::Key path=[:user]>, :name=>:user}>>
49
-
50
- puts user_rule.({}).inspect
51
- #<Dry::Logic::Result::Named success?=false input={} rule=#<Dry::Logic::Rule::Key predicate=#<Dry::Logic::Predicate id=:filled? args=[nil]> options={:evaluator=>#<Dry::Logic::Evaluator::Key path=[:user]>, :name=>:user}>>
52
- ```
27
+ Bug reports and pull requests are welcome on GitHub at https://github.com/dry-rb/dry-logic.
53
28
 
54
29
  ## License
55
30
 
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require 'dry/logic'
5
+ require 'dry/logic/predicates'
6
+
7
+ include Dry::Logic
8
+
9
+ require "irb"
10
+ IRB.start
@@ -1,4 +1,3 @@
1
- # coding: utf-8
2
1
  require File.expand_path('../lib/dry/logic/version', __FILE__)
3
2
 
4
3
  Gem::Specification.new do |spec|
@@ -7,11 +6,10 @@ Gem::Specification.new do |spec|
7
6
  spec.authors = ['Piotr Solnica']
8
7
  spec.email = ['piotr.solnica@gmail.com']
9
8
  spec.summary = 'Predicate logic with rule composition'
10
- spec.homepage = 'https://github.com/dryrb/dry-logic'
9
+ spec.homepage = 'https://github.com/dry-rb/dry-logic'
11
10
  spec.license = 'MIT'
12
11
 
13
12
  spec.files = `git ls-files -z`.split("\x0")
14
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
15
13
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
16
14
  spec.require_paths = ['lib']
17
15
 
@@ -3,17 +3,12 @@ require 'dry/logic/predicates'
3
3
 
4
4
  include Dry::Logic
5
5
 
6
- user_present = Rule::Key.new(Predicates[:filled?], name: :user)
7
- has_min_age = Rule::Key.new(Predicates[:int?], name: [:user, :age]) & Rule::Key.new(Predicates[:gt?].curry(18), name: [:user, :age])
6
+ user_present = Rule::Predicate.new(Predicates[:key?]).curry(:user)
8
7
 
9
- user_rule = user_present & has_min_age
10
-
11
- puts user_rule.(user: { age: 19 }).inspect
8
+ has_min_age = Operations::Key.new(Rule::Predicate.new(Predicates[:gt?]).curry(18), name: [:user, :age])
12
9
 
13
- puts user_rule.(user: { age: 18 }).inspect
14
-
15
- puts user_rule.(user: { age: 'seventeen' }).inspect
10
+ user_rule = user_present & has_min_age
16
11
 
17
- puts user_rule.(user: { }).inspect
12
+ puts user_rule.(user: { age: 19 }).success?
18
13
 
19
- puts user_rule.({}).inspect
14
+ puts user_rule.(user: { age: 18 }).success?
@@ -49,11 +49,11 @@ module Dry
49
49
  rule[evaluator[hash]]
50
50
  end
51
51
 
52
- def ast(input = nil)
53
- if input
54
- [type, [path, rule.ast(evaluator[input])]]
55
- else
52
+ def ast(input = Undefined)
53
+ if input.equal?(Undefined) || !input.is_a?(Hash)
56
54
  [type, [path, rule.ast]]
55
+ else
56
+ [type, [path, rule.ast(evaluator[input])]]
57
57
  end
58
58
  end
59
59
 
@@ -10,7 +10,11 @@ module Dry
10
10
  end
11
11
 
12
12
  def call(input)
13
- Result.new(!rule[input], id) { ast(input) }
13
+ Result.new(rule.(input).failure?, id) { ast(input) }
14
+ end
15
+
16
+ def [](input)
17
+ !rule[input]
14
18
  end
15
19
  end
16
20
  end
@@ -14,9 +14,10 @@ module Dry
14
14
  input.kind_of?(type)
15
15
  end
16
16
 
17
- def none?(input)
17
+ def nil?(input)
18
18
  input.nil?
19
19
  end
20
+ alias_method :none?, :nil?
20
21
 
21
22
  def key?(name, input)
22
23
  input.key?(name)
@@ -166,6 +167,10 @@ module Dry
166
167
  left.eql?(right)
167
168
  end
168
169
 
170
+ def is?(left, right)
171
+ left.equal?(right)
172
+ end
173
+
169
174
  def not_eql?(left, right)
170
175
  !left.eql?(right)
171
176
  end
@@ -178,8 +183,18 @@ module Dry
178
183
  value.equal?(false)
179
184
  end
180
185
 
181
- def format?(regex, input)
182
- !regex.match(input).nil?
186
+ if RUBY_VERSION < '2.4'
187
+ def format?(regex, input)
188
+ !regex.match(input).nil?
189
+ end
190
+ else
191
+ def format?(regex, input)
192
+ regex.match?(input)
193
+ end
194
+ end
195
+
196
+ def case?(pattern, input)
197
+ pattern === input
183
198
  end
184
199
 
185
200
  def predicate(name, &block)
@@ -62,7 +62,7 @@ module Dry
62
62
  end
63
63
 
64
64
  def bind(object)
65
- if predicate.instance_of?(UnboundMethod)
65
+ if UnboundMethod === predicate
66
66
  self.class.new(predicate.bind(object), options)
67
67
  else
68
68
  self.class.new(
@@ -73,7 +73,7 @@ module Dry
73
73
  end
74
74
 
75
75
  def eval_args(object)
76
- with(args: args.map { |arg| arg.instance_of?(UnboundMethod) ? arg.bind(object).() : arg })
76
+ with(args: args.map { |arg| UnboundMethod === arg ? arg.bind(object).() : arg })
77
77
  end
78
78
 
79
79
  def with(new_opts)
@@ -1,5 +1,7 @@
1
1
  require 'dry/core/constants'
2
+
2
3
  require 'dry/logic/rule'
4
+ require 'dry/logic/rule/predicate'
3
5
 
4
6
  module Dry
5
7
  module Logic
@@ -1,5 +1,5 @@
1
1
  module Dry
2
2
  module Logic
3
- VERSION = '0.4.1'.freeze
3
+ VERSION = '0.5.0'.freeze
4
4
  end
5
5
  end
@@ -1,7 +1,7 @@
1
1
  require 'dry/logic/predicates'
2
2
 
3
3
  RSpec.shared_examples 'predicates' do
4
- let(:none?) { Dry::Logic::Predicates[:none?] }
4
+ let(:nil?) { Dry::Logic::Predicates[:nil?] }
5
5
 
6
6
  let(:array?) { Dry::Logic::Predicates[:array?] }
7
7
 
@@ -30,6 +30,10 @@ RSpec.shared_examples 'predicates' do
30
30
  let(:eql?) { Dry::Logic::Predicates[:eql?] }
31
31
 
32
32
  let(:size?) { Dry::Logic::Predicates[:size?] }
33
+
34
+ let(:case?) { Dry::Logic::Predicates[:case?] }
35
+
36
+ let(:equal?) { Dry::Logic::Predicates[:equal?] }
33
37
  end
34
38
 
35
39
  RSpec.shared_examples 'a passing predicate' do
@@ -1,7 +1,13 @@
1
- if RUBY_ENGINE == 'ruby' && ENV['CI'] == 'true'
2
- require 'simplecov'
3
- SimpleCov.start do
4
- add_filter 'spec/'
1
+ if RUBY_ENGINE == 'ruby' && ENV['COVERAGE'] == 'true'
2
+ require 'yaml'
3
+ rubies = YAML.load(File.read(File.join(__dir__, '..', '.travis.yml')))['rvm']
4
+ latest_mri = rubies.select { |v| v =~ /\A\d+\.\d+.\d+\z/ }.max
5
+
6
+ if RUBY_VERSION == latest_mri
7
+ require 'simplecov'
8
+ SimpleCov.start do
9
+ add_filter '/spec/'
10
+ end
5
11
  end
6
12
  end
7
13
 
@@ -23,4 +29,6 @@ include Dry::Core::Constants
23
29
 
24
30
  RSpec.configure do |config|
25
31
  config.disable_monkey_patching!
32
+
33
+ config.warnings = true
26
34
  end
@@ -92,6 +92,20 @@ RSpec.describe Operations::Key do
92
92
  end
93
93
  end
94
94
 
95
+ describe '#ast' do
96
+ it 'returns ast without the input' do
97
+ expect(operation.ast).to eql(
98
+ [:key, [:user, [:predicate, [:key?, [[:name, :age], [:input, Undefined]]]]]]
99
+ )
100
+ end
101
+
102
+ it 'returns ast with the input' do
103
+ expect(operation.ast(user: 'jane')).to eql(
104
+ [:key, [:user, [:predicate, [:key?, [[:name, :age], [:input, 'jane']]]]]]
105
+ )
106
+ end
107
+ end
108
+
95
109
  describe '#and' do
96
110
  subject(:operation) do
97
111
  Operations::Key.new(Rule::Predicate.new(str?), name: [:user, :name])
@@ -10,6 +10,15 @@ RSpec.describe Operations::Negation do
10
10
  expect(operation.('19')).to be_success
11
11
  expect(operation.(17)).to be_failure
12
12
  end
13
+
14
+ context 'double negation' do
15
+ subject(:double_negation) { Operations::Negation.new(operation) }
16
+
17
+ it 'works as rule' do
18
+ expect(double_negation.('19')).to be_failure
19
+ expect(double_negation.(17)).to be_success
20
+ end
21
+ end
13
22
  end
14
23
 
15
24
  describe '#to_ast' do
@@ -3,7 +3,7 @@ RSpec.describe Operations::Or do
3
3
 
4
4
  include_context 'predicates'
5
5
 
6
- let(:left) { Rule::Predicate.new(none?) }
6
+ let(:left) { Rule::Predicate.new(nil?) }
7
7
  let(:right) { Rule::Predicate.new(gt?).curry(18) }
8
8
 
9
9
  let(:other) do
@@ -22,7 +22,7 @@ RSpec.describe Operations::Or do
22
22
  it 'returns ast' do
23
23
  expect(operation.to_ast).to eql(
24
24
  [:or, [
25
- [:predicate, [:none?, [[:input, Undefined]]]],
25
+ [:predicate, [:nil?, [[:input, Undefined]]]],
26
26
  [:predicate, [:gt?, [[:num, 18], [:input, Undefined]]]]]
27
27
  ]
28
28
  )
@@ -31,7 +31,7 @@ RSpec.describe Operations::Or do
31
31
  it 'returns result ast' do
32
32
  expect(operation.(17).to_ast).to eql(
33
33
  [:or, [
34
- [:predicate, [:none?, [[:input, 17]]]],
34
+ [:predicate, [:nil?, [[:input, 17]]]],
35
35
  [:predicate, [:gt?, [[:num, 18], [:input, 17]]]]]
36
36
  ]
37
37
  )
@@ -40,7 +40,7 @@ RSpec.describe Operations::Or do
40
40
  it 'returns failure result ast' do
41
41
  expect(operation.with(id: :age).(17).to_ast).to eql(
42
42
  [:failure, [:age, [:or, [
43
- [:predicate, [:none?, [[:input, 17]]]],
43
+ [:predicate, [:nil?, [[:input, 17]]]],
44
44
  [:predicate, [:gt?, [[:num, 18], [:input, 17]]]]]
45
45
  ]]]
46
46
  )
@@ -67,7 +67,7 @@ RSpec.describe Operations::Or do
67
67
 
68
68
  describe '#to_s' do
69
69
  it 'returns string representation' do
70
- expect(operation.to_s).to eql('none? OR gt?(18)')
70
+ expect(operation.to_s).to eql('nil? OR gt?(18)')
71
71
  end
72
72
  end
73
73
  end
@@ -0,0 +1,33 @@
1
+ require 'dry/logic/predicates'
2
+
3
+ RSpec.describe Dry::Logic::Predicates do
4
+ describe '#case?' do
5
+ let(:predicate_name) { :case? }
6
+
7
+ context 'when the value matches the pattern' do
8
+ let(:arguments_list) do
9
+ [
10
+ [11, 11],
11
+ [:odd?.to_proc, 11],
12
+ [/\Af/, 'foo'],
13
+ [Integer, 11]
14
+ ]
15
+ end
16
+
17
+ it_behaves_like 'a passing predicate'
18
+ end
19
+
20
+ context "when the value doesn't match the pattern" do
21
+ let(:arguments_list) do
22
+ [
23
+ [13, 14],
24
+ [:odd?.to_proc, 12],
25
+ [/\Af/, 'bar'],
26
+ [String, 11]
27
+ ]
28
+ end
29
+
30
+ it_behaves_like 'a failing predicate'
31
+ end
32
+ end
33
+ end
@@ -11,7 +11,7 @@ RSpec.describe Dry::Logic::Predicates, '#eql?' do
11
11
  it_behaves_like 'a passing predicate'
12
12
  end
13
13
 
14
- context 'with value is not empty' do
14
+ context 'with value is not equal to the arg' do
15
15
  let(:arguments_list) do
16
16
  [['Bar', 'Foo']]
17
17
  end
@@ -1,56 +1,24 @@
1
1
  require 'dry/logic/predicates'
2
2
 
3
- RSpec.describe Dry::Logic::Predicates do
4
- describe '#includes?' do
5
- let(:predicate_name) { :includes? }
3
+ RSpec.describe Dry::Logic::Predicates, '#is?' do
4
+ let(:predicate_name) { :is? }
5
+ let(:one) { Object.new }
6
+ let(:two) { Object.new }
6
7
 
7
- context 'when input includes value' do
8
- let(:arguments_list) do
9
- [
10
- ['Jill', ['Jill', 'John']],
11
- ['John', ['Jill', 'John']],
12
- [1, 1..2],
13
- [2, 1..2],
14
- ['Hello', 'Hello World'],
15
- ['World', 'Hello World'],
16
- [:bar, { bar: 0 }],
17
- [nil, [nil, false]],
18
- [false, [nil, false]]
19
- ]
20
- end
21
-
22
- it_behaves_like 'a passing predicate'
8
+ context 'when value is equal to the arg' do
9
+ let(:arguments_list) do
10
+ [[one, one], [:one, :one]]
23
11
  end
24
12
 
25
- context 'with input of invalid type' do
26
- let(:arguments_list) do
27
- [
28
- [2, 1],
29
- [1, nil],
30
- ["foo", 1],
31
- [1, "foo"],
32
- [1..2, "foo"],
33
- ["foo", 1..2],
34
- [:key, "foo"]
35
- ]
36
- end
13
+ it_behaves_like 'a passing predicate'
14
+ end
37
15
 
38
- it_behaves_like 'a failing predicate'
16
+ context 'with value is not equal to the arg' do
17
+ let(:arguments_list) do
18
+ # Strings are not equal. Yet
19
+ [[one, two], ['one', 'one']]
39
20
  end
40
21
 
41
- context 'with input excludes value' do
42
- let(:arguments_list) do
43
- [
44
- ['Jack', ['Jill', 'John']],
45
- [0, 1..2],
46
- [3, 1..2],
47
- ['foo', 'Hello World'],
48
- [:foo, { bar: 0 }],
49
- [true, [nil, false]]
50
- ]
51
- end
52
-
53
- it_behaves_like 'a failing predicate'
54
- end
22
+ it_behaves_like 'a failing predicate'
55
23
  end
56
24
  end
@@ -1,8 +1,8 @@
1
1
  require 'dry/logic/predicates'
2
2
 
3
3
  RSpec.describe Dry::Logic::Predicates do
4
- describe '#none?' do
5
- let(:predicate_name) { :none? }
4
+ describe '#nil?' do
5
+ let(:predicate_name) { :nil? }
6
6
 
7
7
  context 'when value is nil' do
8
8
  let(:arguments_list) { [[nil]] }
@@ -4,6 +4,32 @@ RSpec.describe Dry::Logic::Rule do
4
4
  let(:predicate) { -> { true } }
5
5
  let(:options) { {} }
6
6
 
7
+ let(:schema) do
8
+ Class.new(BasicObject) do
9
+ define_method(:class, Kernel.instance_method(:class))
10
+
11
+ def method_missing(m, *)
12
+ if m.to_s.end_with?('?')
13
+ self.class.new
14
+ else
15
+ super
16
+ end
17
+ end
18
+
19
+ def to_proc
20
+ -> value { value }
21
+ end
22
+
23
+ def arity
24
+ 1
25
+ end
26
+
27
+ def parameters
28
+ [[:req, :value]]
29
+ end
30
+ end.new
31
+ end
32
+
7
33
  it_behaves_like Dry::Logic::Rule
8
34
 
9
35
  describe '.new' do
@@ -80,15 +106,36 @@ RSpec.describe Dry::Logic::Rule do
80
106
  expect(bound.options[:parameters]).to eql(rule.parameters)
81
107
  end
82
108
  end
109
+
110
+ context 'with a schema instance' do
111
+ let(:object) { schema }
112
+ let(:predicate) { schema }
113
+
114
+ it 'returns a new with its predicate executed in the context of the provided object' do
115
+ expect(bound.(true)).to be_success
116
+ expect(bound.(false)).to be_failure
117
+ end
118
+ end
83
119
  end
84
120
 
85
121
  describe '#eval_args' do
86
- let(:options) { { args: [1, klass.instance_method(:num), :foo] } }
87
- let(:klass) { Class.new { def num; 7; end } }
88
- let(:object) { klass.new }
122
+ context 'with an unbound method' do
123
+ let(:options) { { args: [1, klass.instance_method(:num), :foo] } }
124
+ let(:klass) { Class.new { def num; 7; end } }
125
+ let(:object) { klass.new }
89
126
 
90
- it 'evaluates args in the context of the provided object' do
91
- expect(rule.eval_args(object).args).to eql([1, 7, :foo])
127
+ it 'evaluates args in the context of the provided object' do
128
+ expect(rule.eval_args(object).args).to eql([1, 7, :foo])
129
+ end
130
+ end
131
+
132
+ context 'with a schema instance' do
133
+ let(:options) { { args: [1, schema, :foo] } }
134
+ let(:object) { Object.new }
135
+
136
+ it 'returns a new with its predicate executed in the context of the provided object' do
137
+ expect(rule.eval_args(object).args).to eql([1, schema, :foo])
138
+ end
92
139
  end
93
140
  end
94
141
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dry-logic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.5.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: 2017-01-23 00:00:00.000000000 Z
11
+ date: 2019-01-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-core
@@ -114,10 +114,12 @@ files:
114
114
  - ".rubocop_todo.yml"
115
115
  - ".travis.yml"
116
116
  - CHANGELOG.md
117
+ - CONTRIBUTING.md
117
118
  - Gemfile
118
119
  - LICENSE
119
120
  - README.md
120
121
  - Rakefile
122
+ - bin/console
121
123
  - dry-logic.gemspec
122
124
  - examples/basic.rb
123
125
  - lib/dry-logic.rb
@@ -164,6 +166,7 @@ files:
164
166
  - spec/unit/predicates/array_spec.rb
165
167
  - spec/unit/predicates/attr_spec.rb
166
168
  - spec/unit/predicates/bool_spec.rb
169
+ - spec/unit/predicates/case_spec.rb
167
170
  - spec/unit/predicates/date_spec.rb
168
171
  - spec/unit/predicates/date_time_spec.rb
169
172
  - spec/unit/predicates/decimal_spec.rb
@@ -199,7 +202,7 @@ files:
199
202
  - spec/unit/rule/predicate_spec.rb
200
203
  - spec/unit/rule_compiler_spec.rb
201
204
  - spec/unit/rule_spec.rb
202
- homepage: https://github.com/dryrb/dry-logic
205
+ homepage: https://github.com/dry-rb/dry-logic
203
206
  licenses:
204
207
  - MIT
205
208
  metadata: {}
@@ -218,8 +221,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
218
221
  - !ruby/object:Gem::Version
219
222
  version: '0'
220
223
  requirements: []
221
- rubyforge_project:
222
- rubygems_version: 2.6.9
224
+ rubygems_version: 3.0.2
223
225
  signing_key:
224
226
  specification_version: 4
225
227
  summary: Predicate logic with rule composition
@@ -243,6 +245,7 @@ test_files:
243
245
  - spec/unit/predicates/array_spec.rb
244
246
  - spec/unit/predicates/attr_spec.rb
245
247
  - spec/unit/predicates/bool_spec.rb
248
+ - spec/unit/predicates/case_spec.rb
246
249
  - spec/unit/predicates/date_spec.rb
247
250
  - spec/unit/predicates/date_time_spec.rb
248
251
  - spec/unit/predicates/decimal_spec.rb