dry-logic 1.0.4 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +113 -25
  3. data/LICENSE +1 -1
  4. data/README.md +12 -14
  5. data/dry-logic.gemspec +26 -20
  6. data/lib/dry-logic.rb +1 -1
  7. data/lib/dry/logic.rb +2 -2
  8. data/lib/dry/logic/evaluator.rb +1 -1
  9. data/lib/dry/logic/operations.rb +11 -11
  10. data/lib/dry/logic/operations/abstract.rb +3 -3
  11. data/lib/dry/logic/operations/and.rb +3 -3
  12. data/lib/dry/logic/operations/attr.rb +1 -1
  13. data/lib/dry/logic/operations/binary.rb +1 -1
  14. data/lib/dry/logic/operations/check.rb +3 -3
  15. data/lib/dry/logic/operations/each.rb +2 -2
  16. data/lib/dry/logic/operations/implication.rb +2 -2
  17. data/lib/dry/logic/operations/key.rb +3 -3
  18. data/lib/dry/logic/operations/negation.rb +2 -2
  19. data/lib/dry/logic/operations/or.rb +2 -2
  20. data/lib/dry/logic/operations/set.rb +3 -3
  21. data/lib/dry/logic/operations/unary.rb +1 -1
  22. data/lib/dry/logic/operations/xor.rb +2 -2
  23. data/lib/dry/logic/operators.rb +4 -4
  24. data/lib/dry/logic/predicates.rb +33 -8
  25. data/lib/dry/logic/result.rb +2 -2
  26. data/lib/dry/logic/rule.rb +8 -8
  27. data/lib/dry/logic/rule/interface.rb +32 -37
  28. data/lib/dry/logic/rule/predicate.rb +3 -3
  29. data/lib/dry/logic/rule_compiler.rb +3 -3
  30. data/lib/dry/logic/version.rb +1 -1
  31. metadata +17 -166
  32. data/.codeclimate.yml +0 -12
  33. data/.github/ISSUE_TEMPLATE/----please-don-t-ask-for-support-via-issues.md +0 -10
  34. data/.github/ISSUE_TEMPLATE/---bug-report.md +0 -34
  35. data/.github/ISSUE_TEMPLATE/---feature-request.md +0 -18
  36. data/.github/workflows/ci.yml +0 -70
  37. data/.github/workflows/docsite.yml +0 -34
  38. data/.github/workflows/sync_configs.yml +0 -34
  39. data/.gitignore +0 -9
  40. data/.rspec +0 -4
  41. data/.rubocop.yml +0 -89
  42. data/CODE_OF_CONDUCT.md +0 -13
  43. data/CONTRIBUTING.md +0 -29
  44. data/Gemfile +0 -16
  45. data/Rakefile +0 -14
  46. data/benchmarks/rule_application.rb +0 -30
  47. data/benchmarks/setup.rb +0 -13
  48. data/bin/console +0 -11
  49. data/docsite/source/index.html.md +0 -54
  50. data/docsite/source/operations.html.md +0 -62
  51. data/docsite/source/predicates.html.md +0 -102
  52. data/examples/basic.rb +0 -16
  53. data/spec/integration/result_spec.rb +0 -61
  54. data/spec/integration/rule_spec.rb +0 -55
  55. data/spec/shared/predicates.rb +0 -59
  56. data/spec/shared/rule.rb +0 -74
  57. data/spec/spec_helper.rb +0 -30
  58. data/spec/support/mutant.rb +0 -11
  59. data/spec/unit/operations/and_spec.rb +0 -70
  60. data/spec/unit/operations/attr_spec.rb +0 -29
  61. data/spec/unit/operations/check_spec.rb +0 -51
  62. data/spec/unit/operations/each_spec.rb +0 -49
  63. data/spec/unit/operations/implication_spec.rb +0 -32
  64. data/spec/unit/operations/key_spec.rb +0 -135
  65. data/spec/unit/operations/negation_spec.rb +0 -51
  66. data/spec/unit/operations/or_spec.rb +0 -75
  67. data/spec/unit/operations/set_spec.rb +0 -43
  68. data/spec/unit/operations/xor_spec.rb +0 -63
  69. data/spec/unit/predicates/array_spec.rb +0 -43
  70. data/spec/unit/predicates/attr_spec.rb +0 -31
  71. data/spec/unit/predicates/bool_spec.rb +0 -36
  72. data/spec/unit/predicates/bytesize_spec.rb +0 -48
  73. data/spec/unit/predicates/case_spec.rb +0 -35
  74. data/spec/unit/predicates/date_spec.rb +0 -33
  75. data/spec/unit/predicates/date_time_spec.rb +0 -33
  76. data/spec/unit/predicates/decimal_spec.rb +0 -34
  77. data/spec/unit/predicates/empty_spec.rb +0 -40
  78. data/spec/unit/predicates/eql_spec.rb +0 -23
  79. data/spec/unit/predicates/even_spec.rb +0 -33
  80. data/spec/unit/predicates/excluded_from_spec.rb +0 -37
  81. data/spec/unit/predicates/excludes_spec.rb +0 -58
  82. data/spec/unit/predicates/false_spec.rb +0 -37
  83. data/spec/unit/predicates/filled_spec.rb +0 -40
  84. data/spec/unit/predicates/float_spec.rb +0 -33
  85. data/spec/unit/predicates/format_spec.rb +0 -23
  86. data/spec/unit/predicates/gt_spec.rb +0 -42
  87. data/spec/unit/predicates/gteq_spec.rb +0 -42
  88. data/spec/unit/predicates/hash_spec.rb +0 -40
  89. data/spec/unit/predicates/included_in_spec.rb +0 -37
  90. data/spec/unit/predicates/includes_spec.rb +0 -24
  91. data/spec/unit/predicates/int_spec.rb +0 -36
  92. data/spec/unit/predicates/key_spec.rb +0 -31
  93. data/spec/unit/predicates/lt_spec.rb +0 -42
  94. data/spec/unit/predicates/lteq_spec.rb +0 -42
  95. data/spec/unit/predicates/max_bytesize_spec.rb +0 -39
  96. data/spec/unit/predicates/max_size_spec.rb +0 -51
  97. data/spec/unit/predicates/min_bytesize_spec.rb +0 -39
  98. data/spec/unit/predicates/min_size_spec.rb +0 -51
  99. data/spec/unit/predicates/none_spec.rb +0 -30
  100. data/spec/unit/predicates/not_eql_spec.rb +0 -23
  101. data/spec/unit/predicates/number_spec.rb +0 -39
  102. data/spec/unit/predicates/odd_spec.rb +0 -33
  103. data/spec/unit/predicates/respond_to_spec.rb +0 -31
  104. data/spec/unit/predicates/size_spec.rb +0 -57
  105. data/spec/unit/predicates/str_spec.rb +0 -34
  106. data/spec/unit/predicates/time_spec.rb +0 -33
  107. data/spec/unit/predicates/true_spec.rb +0 -37
  108. data/spec/unit/predicates/type_spec.rb +0 -37
  109. data/spec/unit/predicates/uuid_v4_spec.rb +0 -29
  110. data/spec/unit/predicates_spec.rb +0 -25
  111. data/spec/unit/rule/predicate_spec.rb +0 -55
  112. data/spec/unit/rule_compiler_spec.rb +0 -129
  113. data/spec/unit/rule_spec.rb +0 -213
@@ -1,34 +0,0 @@
1
- # this file is managed by dry-rb/devtools project
2
-
3
- name: sync_configs
4
-
5
- on:
6
- repository_dispatch:
7
-
8
- jobs:
9
- sync-configs:
10
- runs-on: ubuntu-latest
11
- if: github.event.action == 'sync_configs'
12
- steps:
13
- - uses: actions/checkout@v1
14
- - name: Update configuration files from devtools
15
- env:
16
- GITHUB_LOGIN: dry-bot
17
- GITHUB_TOKEN: ${{ secrets.GH_PAT }}
18
- run: |
19
- git clone https://github.com/dry-rb/devtools.git tmp/devtools
20
-
21
- if [ -f ".github/workflows/custom_ci.yml" ]; then
22
- rsync -av --exclude '.github/workflows/ci.yml' tmp/devtools/shared/ . ;
23
- else
24
- rsync -av tmp/devtools/shared/ . ;
25
- fi
26
-
27
- git config --local user.email "dry-bot@dry-rb.org"
28
- git config --local user.name "dry-bot"
29
- git add -A
30
- git commit -m "[devtools] config sync" || echo "nothing changed"
31
- - name: Push changes
32
- uses: ad-m/github-push-action@master
33
- with:
34
- github_token: ${{ secrets.GH_PAT }}
data/.gitignore DELETED
@@ -1,9 +0,0 @@
1
- .DS_Store
2
- coverage
3
- /.bundle
4
- vendor/bundle
5
- tmp/
6
- pkg/
7
- .idea/
8
- Gemfile.lock
9
-
data/.rspec DELETED
@@ -1,4 +0,0 @@
1
- --color
2
- --require spec_helper
3
- --order random
4
-
@@ -1,89 +0,0 @@
1
- # this file is managed by dry-rb/devtools project
2
-
3
- AllCops:
4
- TargetRubyVersion: 2.4
5
-
6
- Style/EachWithObject:
7
- Enabled: false
8
-
9
- Style/StringLiterals:
10
- Enabled: true
11
- EnforcedStyle: single_quotes
12
-
13
- Style/Alias:
14
- Enabled: false
15
-
16
- Style/LambdaCall:
17
- Enabled: false
18
-
19
- Style/StabbyLambdaParentheses:
20
- Enabled: false
21
-
22
- Style/FormatString:
23
- Enabled: false
24
-
25
- Style/Documentation:
26
- Enabled: false
27
-
28
- Layout/SpaceInLambdaLiteral:
29
- Enabled: false
30
-
31
- Layout/MultilineMethodCallIndentation:
32
- Enabled: true
33
- EnforcedStyle: indented
34
-
35
- Metrics/LineLength:
36
- Max: 100
37
-
38
- Metrics/MethodLength:
39
- Max: 22
40
-
41
- Metrics/ClassLength:
42
- Max: 150
43
-
44
- Metrics/AbcSize:
45
- Max: 20
46
-
47
- Metrics/BlockLength:
48
- Enabled: false
49
-
50
- Metrics/CyclomaticComplexity:
51
- Enabled: true
52
- Max: 10
53
-
54
- Lint/BooleanSymbol:
55
- Enabled: false
56
-
57
- Style/AccessModifierDeclarations:
58
- Enabled: false
59
-
60
- Style/BlockDelimiters:
61
- Enabled: false
62
-
63
- Layout/IndentFirstArrayElement:
64
- EnforcedStyle: consistent
65
-
66
- Style/ClassAndModuleChildren:
67
- Exclude:
68
- - "spec/**/*_spec.rb"
69
-
70
- Lint/HandleExceptions:
71
- Exclude:
72
- - "spec/spec_helper.rb"
73
-
74
- Naming/FileName:
75
- Exclude:
76
- - "lib/dry-*.rb"
77
-
78
- Style/SymbolArray:
79
- Exclude:
80
- - "spec/**/*_spec.rb"
81
-
82
- Style/ConditionalAssignment:
83
- Enabled: false
84
-
85
- Naming/MethodName:
86
- Enabled: false
87
-
88
- Style/AsciiComments:
89
- Enabled: false
@@ -1,13 +0,0 @@
1
- # Contributor Code of Conduct
2
-
3
- As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
4
-
5
- We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion.
6
-
7
- Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
8
-
9
- Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
10
-
11
- Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
12
-
13
- This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.4.0, available at [https://www.contributor-covenant.org/version/1/4/code-of-conduct](https://www.contributor-covenant.org/version/1/4/code-of-conduct)
@@ -1,29 +0,0 @@
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 [discourse.dry-rb.org](https://discourse.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 [discourse.dry-rb.org](http://discourse.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 [discourse.dry-rb.org](https://discourse.dry-rb.org) or join [our chat](https://dry-rb.zulipchat.com).
data/Gemfile DELETED
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- source 'https://rubygems.org'
4
-
5
- gemspec
6
-
7
- group :test do
8
- gem 'simplecov', require: false, platform: :mri
9
- end
10
-
11
- group :tools do
12
- gem 'pry-byebug', platform: :mri
13
- gem 'benchmark-ips', platform: :mri
14
- gem 'hotch', platform: :mri
15
- gem 'ossy', git: 'https://github.com/solnic/ossy.git', branch: 'master'
16
- end
data/Rakefile DELETED
@@ -1,14 +0,0 @@
1
- #!/usr/bin/env rake
2
- # frozen_string_literal: true
3
-
4
- require 'bundler/gem_tasks'
5
-
6
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'lib'))
7
-
8
- require 'rspec/core'
9
- require 'rspec/core/rake_task'
10
-
11
- task default: :spec
12
-
13
- desc 'Run all specs in spec directory'
14
- RSpec::Core::RakeTask.new(:spec)
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'setup'
4
-
5
- unless Dry::Logic::Rule.respond_to?(:build)
6
- Dry::Logic::Rule.singleton_class.alias_method(:build, :new)
7
- end
8
-
9
- predicates = Dry::Logic::Predicates
10
-
11
- type_check = Dry::Logic::Rule.build(predicates[:type?]).curry(Integer)
12
- int_check = Dry::Logic::Rule.build(predicates[:int?])
13
- key_check = Dry::Logic::Rule.build(predicates[:key?]).curry(:user)
14
- with_user = { user: {} }
15
- without_user = {}
16
-
17
- comparison = Dry::Logic::Rule.build(predicates[:gteq?]).curry(18)
18
-
19
- Benchmark.ips do |x|
20
- x.report("type check - success") { type_check.(0) }
21
- x.report("type check - failure") { type_check.('0') }
22
- x.report("int check - success") { int_check.(0) }
23
- x.report("int check - failure") { int_check.('0') }
24
- x.report("key check - success") { key_check.(with_user) }
25
- x.report("key check - failure") { key_check.(without_user) }
26
- x.report("comparison - success") { comparison.(20) }
27
- x.report("comparison - failure") { comparison.(17) }
28
-
29
- x.compare!
30
- end
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'benchmark/ips'
4
- require 'hotch'
5
- ENV['HOTCH_VIEWER'] ||= 'open'
6
-
7
- require 'dry/logic'
8
- require 'dry/logic/predicates'
9
-
10
- def profile(&block)
11
- Hotch(filter: 'Dry', &block)
12
- end
13
-
@@ -1,11 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require "bundler/setup"
5
- require 'dry/logic'
6
- require 'dry/logic/predicates'
7
-
8
- include Dry::Logic
9
-
10
- require "irb"
11
- IRB.start
@@ -1,54 +0,0 @@
1
- ---
2
- title: Introduction
3
- description: Predicate logic with composable rules
4
- layout: gem-single
5
- type: gem
6
- name: dry-logic
7
- sections:
8
- - predicates
9
- - operations
10
- ---
11
-
12
- Predicate logic and rule composition used by:
13
-
14
- * [dry-types](https://github.com/dry-rb/dry-types) for constrained types
15
- * [dry-validation](https://github.com/dry-rb/dry-validation) for composing validation rules
16
- * your project...?
17
-
18
- ## Synopsis
19
-
20
- ``` ruby
21
- require 'dry/logic'
22
- require 'dry/logic/predicates'
23
-
24
- include Dry::Logic
25
-
26
- # Rule::Predicate will only apply its predicate to its input, that’s all
27
-
28
- # require input to have the key :user
29
- user_present = Rule::Predicate.new(Predicates[:key?]).curry(:user)
30
- # curry allows us to prepare predicates with args, without the input
31
-
32
- # require value to be greater than 18
33
- min_18 = Rule::Predicate.new(Predicates[:gt?]).curry(18)
34
-
35
- # use the min_18 predicate on the the value of user[:age]
36
- has_min_age = Operations::Key.new(min_18, name: [:user, :age])
37
-
38
- user_rule = user_present & has_min_age
39
-
40
- user_rule.(user: { age: 19 }).success?
41
- # => true
42
-
43
- user_rule.(user: { age: 18 }).success?
44
- # => false
45
-
46
- user_rule.(user: { age: 'seventeen' })
47
- # => ArgumentError: comparison of String with 18 failed
48
-
49
- user_rule.(user: { })
50
- # => NoMethodError: undefined method `>' for nil:NilClass
51
-
52
- user_rule.({}).success?
53
- # => false
54
- ```
@@ -1,62 +0,0 @@
1
- ---
2
- title: Operations
3
- layout: gem-single
4
- name: dry-logic
5
- ---
6
-
7
- Dry-logic uses operations to interact with the input passed to the different rules.
8
-
9
- ``` ruby
10
- require 'dry/logic'
11
- require 'dry/logic/predicates'
12
-
13
- include Dry::Logic
14
-
15
- user_present = Rule::Predicate.new(Predicates[:key?]).curry(:user)
16
-
17
- min_18 = Rule::Predicate.new(Predicates[:gt?]).curry(18)
18
-
19
- # Here Operations::Key and Rule::Predicate are use to compose and logic based on the value of a given key e.g [:user, :age]
20
- has_min_age = Operations::Key.new(min_18, name: [:user, :age])
21
- # => #<Dry::Logic::Operations::Key rules=[#<Dry::Logic::Rule::Predicate predicate=#<Method: Module(Dry::Logic::Predicates::Methods)#gt?> options={:args=>[18]}>] options={:name=>[:user, :age], :evaluator=>#<Dry::Logic::Evaluator::Key path=[:user, :age]>, :path=>[:user, :age]}>
22
-
23
- # Thanks to the composable structure of the library we can use multiple Rules and Operations to create custom logic
24
- user_rule = user_present & has_min_age
25
-
26
- user_rule.(user: { age: 19 }).success?
27
- # => true
28
- ```
29
-
30
- * Built-in:
31
- - `and`
32
- - `or`
33
- - `key`
34
- - `attr`
35
- - `binary`
36
- - `check`
37
- - `each`
38
- - `implication`
39
- - `negation`
40
- - `set`
41
- - `xor`
42
-
43
- Another example, lets create the `all?` method from the `Enumerable` module.
44
-
45
- ``` ruby
46
- require 'dry/logic'
47
- require 'dry/logic/predicates'
48
-
49
- include Dry::Logic
50
-
51
- def all?(value)
52
- Operations::Each.new(Rule::Predicate.new(Predicates[:gt?]).curry(value))
53
- end
54
-
55
- all_6 = all?(6)
56
-
57
- all_6.([6,7,8,9]).success?
58
- # => true
59
-
60
- all_6.([1,2,3,4]).success?
61
- # => false
62
- ```
@@ -1,102 +0,0 @@
1
- ---
2
- title: Predicates
3
- layout: gem-single
4
- name: dry-logic
5
- ---
6
-
7
- Dry-logic comes with a lot predicates to compose multiple rules:
8
-
9
- ``` ruby
10
- require 'dry/logic'
11
- require 'dry/logic/predicates'
12
-
13
- include Dry::Logic
14
- ```
15
-
16
- Now you can access all built-in predicates:
17
-
18
- ``` ruby
19
- Predicates[:key?]
20
- # => #<Method: Module(Dry::Logic::Predicates::Methods)#key?>
21
- ```
22
-
23
- In the end predicates return true or false.
24
-
25
- ```ruby
26
- Predicates[:key?].(:name, {name: 'John'})
27
- # => true
28
- ```
29
-
30
- * Built-in:
31
- - `type?`
32
- - `none?`
33
- - `key?`
34
- - `attr?`
35
- - `empty?`
36
- - `filled?`
37
- - `bool?`
38
- - `date?`
39
- - `date_time?`
40
- - `time?`
41
- - `number?`
42
- - `int?`
43
- - `float?`
44
- - `decimal?`
45
- - `str?`
46
- - `hash?`
47
- - `array?`
48
- - `odd?`
49
- - `even?`
50
- - `lt?`
51
- - `gt?`
52
- - `lteq?`
53
- - `gteq?`
54
- - `size?`
55
- - `min_size?`
56
- - `max_size?`
57
- - `bytesize?`
58
- - `min_bytesize?`
59
- - `max_bytesize?`
60
- - `inclusion?`
61
- - `exclusion?`
62
- - `included_in?`
63
- - `excluded_from?`
64
- - `includes?`
65
- - `excludes?`
66
- - `eql?`
67
- - `not_eql?`
68
- - `is?`
69
- - `case?`
70
- - `true?`
71
- - `false?`
72
- - `format?`
73
- - `respond_to?`
74
- - `predicate`
75
- - `uuid_v4?`
76
-
77
- With predicates you can build more composable and complex operations:
78
- For example, let's say we want to check that a given input is a hash and has a specify key.
79
-
80
- ``` ruby
81
- require 'dry/logic'
82
- require 'dry/logic/predicates'
83
-
84
- include Dry::Logic
85
-
86
- is_hash = Rule::Predicate.new(Predicates[:type?]).curry(Hash)
87
- # => #<Dry::Logic::Rule::Predicate predicate=#<Method: Module(Dry::Logic::Predicates::Methods)#type?> options={:args=>[:hash]}>
88
- name_key = Rule::Predicate.new(Predicates[:key?]).curry(:name)
89
- # => #<Dry::Logic::Rule::Predicate predicate=#<Method: Module(Dry::Logic::Predicates::Methods)#key?> options={:args=>[:name]}>
90
-
91
- hash_with_key = is_hash & name_key
92
- # => #<Dry::Logic::Operations::And rules=[#<Dry::Logic::Rule::Predicate predicate=#<Method: Module(Dry::Logic::Predicates::Methods)#type?> options={:args=>[:hash]}>, #<Dry::Logic::Rule::Predicate predicate=#<Method: Module(Dry::Logic::Predicates::Methods)#key?> options={:args=>[:name]}>] options={}>
93
-
94
- hash_with_key.(name: 'John').success?
95
- # => true
96
-
97
- hash_with_key.(not_valid: 'John').success?
98
- # => false
99
-
100
- hash_with_key.([1,2]).success?
101
- # => false
102
- ```