dry-logic 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.rspec +3 -0
- data/.rubocop.yml +16 -0
- data/.rubocop_todo.yml +7 -0
- data/.travis.yml +31 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +11 -0
- data/LICENSE +20 -0
- data/README.md +45 -0
- data/Rakefile +12 -0
- data/dry-logic.gemspec +24 -0
- data/examples/basic.rb +13 -0
- data/lib/dry-logic.rb +1 -0
- data/lib/dry/logic.rb +10 -0
- data/lib/dry/logic/predicate.rb +35 -0
- data/lib/dry/logic/predicate_set.rb +23 -0
- data/lib/dry/logic/predicates.rb +129 -0
- data/lib/dry/logic/result.rb +119 -0
- data/lib/dry/logic/rule.rb +91 -0
- data/lib/dry/logic/rule/check.rb +15 -0
- data/lib/dry/logic/rule/composite.rb +63 -0
- data/lib/dry/logic/rule/each.rb +13 -0
- data/lib/dry/logic/rule/group.rb +21 -0
- data/lib/dry/logic/rule/key.rb +17 -0
- data/lib/dry/logic/rule/set.rb +22 -0
- data/lib/dry/logic/rule/value.rb +13 -0
- data/lib/dry/logic/rule_compiler.rb +81 -0
- data/lib/dry/logic/version.rb +5 -0
- data/rakelib/rubocop.rake +18 -0
- data/spec/shared/predicates.rb +41 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/unit/predicate_spec.rb +27 -0
- data/spec/unit/predicates/bool_spec.rb +34 -0
- data/spec/unit/predicates/date_spec.rb +31 -0
- data/spec/unit/predicates/date_time_spec.rb +31 -0
- data/spec/unit/predicates/decimal_spec.rb +32 -0
- data/spec/unit/predicates/empty_spec.rb +38 -0
- data/spec/unit/predicates/eql_spec.rb +21 -0
- data/spec/unit/predicates/exclusion_spec.rb +35 -0
- data/spec/unit/predicates/filled_spec.rb +38 -0
- data/spec/unit/predicates/float_spec.rb +31 -0
- data/spec/unit/predicates/format_spec.rb +21 -0
- data/spec/unit/predicates/gt_spec.rb +40 -0
- data/spec/unit/predicates/gteq_spec.rb +40 -0
- data/spec/unit/predicates/inclusion_spec.rb +35 -0
- data/spec/unit/predicates/int_spec.rb +34 -0
- data/spec/unit/predicates/key_spec.rb +29 -0
- data/spec/unit/predicates/lt_spec.rb +40 -0
- data/spec/unit/predicates/lteq_spec.rb +40 -0
- data/spec/unit/predicates/max_size_spec.rb +49 -0
- data/spec/unit/predicates/min_size_spec.rb +49 -0
- data/spec/unit/predicates/none_spec.rb +28 -0
- data/spec/unit/predicates/size_spec.rb +55 -0
- data/spec/unit/predicates/str_spec.rb +32 -0
- data/spec/unit/predicates/time_spec.rb +31 -0
- data/spec/unit/rule/check_spec.rb +29 -0
- data/spec/unit/rule/conjunction_spec.rb +30 -0
- data/spec/unit/rule/disjunction_spec.rb +38 -0
- data/spec/unit/rule/each_spec.rb +20 -0
- data/spec/unit/rule/group_spec.rb +12 -0
- data/spec/unit/rule/implication_spec.rb +16 -0
- data/spec/unit/rule/key_spec.rb +27 -0
- data/spec/unit/rule/set_spec.rb +32 -0
- data/spec/unit/rule/value_spec.rb +42 -0
- data/spec/unit/rule_compiler_spec.rb +123 -0
- metadata +221 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8ed31141ff3e52c81a9afce4397631ce26372a7e
|
4
|
+
data.tar.gz: ee8d692843523fc91d4e9f6d28a03e4e749362b5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 61463a874fb6281033cba937136a44131df14b59b1fab36532786f47f698eeaa96fbca1cdcc8235ee93b69d66e85da5230bd2c15094720c102024ee01355bc0b
|
7
|
+
data.tar.gz: 48f375ae23737143a1aea7ba6494f47de0aa86548278f66dedd45333473a177f1a3704e0451777ef1b128669e68006fee952ccf10634f0f928ec28fe5942f738
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,16 @@
|
|
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
ADDED
@@ -0,0 +1,7 @@
|
|
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.
|
data/.travis.yml
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
language: ruby
|
2
|
+
sudo: false
|
3
|
+
cache: bundler
|
4
|
+
bundler_args: --without console
|
5
|
+
script:
|
6
|
+
- bundle exec rake spec
|
7
|
+
rvm:
|
8
|
+
- 2.0
|
9
|
+
- 2.1
|
10
|
+
- 2.2
|
11
|
+
- 2.3.0
|
12
|
+
- rbx-2
|
13
|
+
- jruby-9000
|
14
|
+
- ruby-head
|
15
|
+
- jruby-head
|
16
|
+
env:
|
17
|
+
global:
|
18
|
+
- JRUBY_OPTS='--dev -J-Xmx1024M'
|
19
|
+
matrix:
|
20
|
+
allow_failures:
|
21
|
+
- rvm: ruby-head
|
22
|
+
- rvm: jruby-head
|
23
|
+
- rvm: jruby-9000
|
24
|
+
notifications:
|
25
|
+
email: false
|
26
|
+
webhooks:
|
27
|
+
urls:
|
28
|
+
- https://webhooks.gitter.im/e/19098b4253a72c9796db
|
29
|
+
on_success: change # options: [always|never|change] default: always
|
30
|
+
on_failure: always # options: [always|never|change] default: always
|
31
|
+
on_start: false # default: false
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2014 Ruby Object Mapper
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
[gem]: https://rubygems.org/gems/dry-logic
|
2
|
+
[travis]: https://travis-ci.org/dryrb/dry-logic
|
3
|
+
[gemnasium]: https://gemnasium.com/dryrb/dry-logic
|
4
|
+
[codeclimate]: https://codeclimate.com/github/dryrb/dry-logic
|
5
|
+
[coveralls]: https://coveralls.io/r/dryrb/dry-logic
|
6
|
+
[inchpages]: http://inch-ci.org/github/dryrb/dry-logic
|
7
|
+
|
8
|
+
# dry-logic [![Join the chat at https://gitter.im/dryrb/chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/dryrb/chat)
|
9
|
+
|
10
|
+
[![Gem Version](https://badge.fury.io/rb/dry-logic.svg)][gem]
|
11
|
+
[![Build Status](https://travis-ci.org/dryrb/dry-logic.svg?branch=master)][travis]
|
12
|
+
[![Dependency Status](https://gemnasium.com/dryrb/dry-logic.svg)][gemnasium]
|
13
|
+
[![Code Climate](https://codeclimate.com/github/dryrb/dry-logic/badges/gpa.svg)][codeclimate]
|
14
|
+
[![Test Coverage](https://codeclimate.com/github/dryrb/dry-logic/badges/coverage.svg)][codeclimate]
|
15
|
+
[![Inline docs](http://inch-ci.org/github/dryrb/dry-logic.svg?branch=master)][inchpages]
|
16
|
+
|
17
|
+
Predicate logic and rule composition used by:
|
18
|
+
|
19
|
+
* [dry-data](https://github.com/dryrb/dry-data) for constrained types
|
20
|
+
* [dry-validation](https://github.com/dryrb/dry-validation) for composing validation rules
|
21
|
+
* your project...?
|
22
|
+
|
23
|
+
## Synopsis
|
24
|
+
|
25
|
+
``` ruby
|
26
|
+
require 'dry/logic'
|
27
|
+
require 'dry/logic/predicates'
|
28
|
+
|
29
|
+
include Dry::Logic
|
30
|
+
|
31
|
+
user_present = Rule::Key.new(:user, Predicates[:key?])
|
32
|
+
has_min_age = Rule::Key.new(:age, Predicates[:key?]) & Rule::Value.new(:age, Predicates[:gt?].curry(18))
|
33
|
+
|
34
|
+
user_rule = user_present & has_min_age
|
35
|
+
|
36
|
+
user_rule.(user: { age: 19 })
|
37
|
+
# #<Dry::Logic::Result::Value success?=true input=19 rule=#<Dry::Logic::Rule::Value name=:age predicate=#<Dry::Logic::Predicate id=:gt?>>>
|
38
|
+
|
39
|
+
user_rule.(user: { age: 18 })
|
40
|
+
# #<Dry::Logic::Result::Value success?=false input=18 rule=#<Dry::Logic::Rule::Value name=:age predicate=#<Dry::Logic::Predicate id=:gt?>>>
|
41
|
+
```
|
42
|
+
|
43
|
+
## License
|
44
|
+
|
45
|
+
See `LICENSE` file.
|
data/Rakefile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
|
4
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'lib'))
|
5
|
+
|
6
|
+
require 'rspec/core'
|
7
|
+
require 'rspec/core/rake_task'
|
8
|
+
|
9
|
+
task default: :spec
|
10
|
+
|
11
|
+
desc 'Run all specs in spec directory'
|
12
|
+
RSpec::Core::RakeTask.new(:spec)
|
data/dry-logic.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require File.expand_path('../lib/dry/logic/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |spec|
|
5
|
+
spec.name = 'dry-logic'
|
6
|
+
spec.version = Dry::Logic::VERSION
|
7
|
+
spec.authors = ['Piotr Solnica']
|
8
|
+
spec.email = ['piotr.solnica@gmail.com']
|
9
|
+
spec.summary = 'Predicate logic with rule composition'
|
10
|
+
spec.homepage = 'https://github.com/dryrb/dry-logic'
|
11
|
+
spec.license = 'MIT'
|
12
|
+
|
13
|
+
spec.files = `git ls-files -z`.split("\x0")
|
14
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
15
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
16
|
+
spec.require_paths = ['lib']
|
17
|
+
|
18
|
+
spec.add_runtime_dependency 'dry-container', '~> 0.2', '>= 0.2.6'
|
19
|
+
spec.add_runtime_dependency 'dry-equalizer', '~> 0.2'
|
20
|
+
|
21
|
+
spec.add_development_dependency 'bundler'
|
22
|
+
spec.add_development_dependency 'rake'
|
23
|
+
spec.add_development_dependency 'rspec'
|
24
|
+
end
|
data/examples/basic.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'dry/logic'
|
2
|
+
require 'dry/logic/predicates'
|
3
|
+
|
4
|
+
include Dry::Logic
|
5
|
+
|
6
|
+
user_present = Rule::Key.new(:user, Predicates[:key?])
|
7
|
+
has_min_age = Rule::Key.new(:age, Predicates[:key?]) & Rule::Value.new(:age, Predicates[:gt?].curry(18))
|
8
|
+
|
9
|
+
user_rule = user_present & has_min_age
|
10
|
+
|
11
|
+
puts user_rule.(user: { age: 19 }).inspect
|
12
|
+
|
13
|
+
puts user_rule.(user: { age: 18 }).inspect
|
data/lib/dry-logic.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'dry/logic'
|
data/lib/dry/logic.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
module Dry
|
2
|
+
module Logic
|
3
|
+
def self.Predicate(block)
|
4
|
+
case block
|
5
|
+
when Method then Predicate.new(block.name, &block)
|
6
|
+
else raise ArgumentError, 'predicate needs an :id'
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class Predicate
|
11
|
+
include Dry::Equalizer(:id)
|
12
|
+
|
13
|
+
attr_reader :id, :args, :fn
|
14
|
+
|
15
|
+
def initialize(id, *args, &block)
|
16
|
+
@id = id
|
17
|
+
@fn = block
|
18
|
+
@args = args
|
19
|
+
end
|
20
|
+
|
21
|
+
def call(*args)
|
22
|
+
fn.(*args)
|
23
|
+
end
|
24
|
+
|
25
|
+
def curry(*args)
|
26
|
+
self.class.new(id, *args, &fn.curry.(*args))
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_ary
|
30
|
+
[:predicate, [id, args]]
|
31
|
+
end
|
32
|
+
alias_method :to_a, :to_ary
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'dry/logic/predicate'
|
2
|
+
require 'dry-container'
|
3
|
+
|
4
|
+
module Dry
|
5
|
+
module Logic
|
6
|
+
module PredicateSet
|
7
|
+
module Methods
|
8
|
+
def predicate(name, &block)
|
9
|
+
register(name) { Predicate.new(name, &block) }
|
10
|
+
end
|
11
|
+
|
12
|
+
def import(predicate_set)
|
13
|
+
merge(predicate_set)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.extended(other)
|
18
|
+
super
|
19
|
+
other.extend(Methods, Dry::Container::Mixin)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'bigdecimal'
|
2
|
+
require 'bigdecimal/util'
|
3
|
+
require 'date'
|
4
|
+
|
5
|
+
require 'dry/logic/predicate_set'
|
6
|
+
|
7
|
+
module Dry
|
8
|
+
module Logic
|
9
|
+
module Predicates
|
10
|
+
extend Logic::PredicateSet
|
11
|
+
|
12
|
+
def self.included(other)
|
13
|
+
super
|
14
|
+
other.extend(Logic::PredicateSet)
|
15
|
+
other.import(self)
|
16
|
+
end
|
17
|
+
|
18
|
+
predicate(:none?) do |input|
|
19
|
+
input.nil?
|
20
|
+
end
|
21
|
+
|
22
|
+
predicate(:key?) do |name, input|
|
23
|
+
input.key?(name)
|
24
|
+
end
|
25
|
+
|
26
|
+
predicate(:empty?) do |input|
|
27
|
+
case input
|
28
|
+
when String, Array, Hash then input.empty?
|
29
|
+
when nil then true
|
30
|
+
else
|
31
|
+
false
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
predicate(:filled?) do |input|
|
36
|
+
!self[:empty?].(input)
|
37
|
+
end
|
38
|
+
|
39
|
+
predicate(:bool?) do |input|
|
40
|
+
input.is_a?(TrueClass) || input.is_a?(FalseClass)
|
41
|
+
end
|
42
|
+
|
43
|
+
predicate(:date?) do |input|
|
44
|
+
input.is_a?(Date)
|
45
|
+
end
|
46
|
+
|
47
|
+
predicate(:date_time?) do |input|
|
48
|
+
input.is_a?(DateTime)
|
49
|
+
end
|
50
|
+
|
51
|
+
predicate(:time?) do |input|
|
52
|
+
input.is_a?(Time)
|
53
|
+
end
|
54
|
+
|
55
|
+
predicate(:int?) do |input|
|
56
|
+
input.is_a?(Fixnum)
|
57
|
+
end
|
58
|
+
|
59
|
+
predicate(:float?) do |input|
|
60
|
+
input.is_a?(Float)
|
61
|
+
end
|
62
|
+
|
63
|
+
predicate(:decimal?) do |input|
|
64
|
+
input.is_a?(BigDecimal)
|
65
|
+
end
|
66
|
+
|
67
|
+
predicate(:str?) do |input|
|
68
|
+
input.is_a?(String)
|
69
|
+
end
|
70
|
+
|
71
|
+
predicate(:hash?) do |input|
|
72
|
+
input.is_a?(Hash)
|
73
|
+
end
|
74
|
+
|
75
|
+
predicate(:array?) do |input|
|
76
|
+
input.is_a?(Array)
|
77
|
+
end
|
78
|
+
|
79
|
+
predicate(:lt?) do |num, input|
|
80
|
+
input < num
|
81
|
+
end
|
82
|
+
|
83
|
+
predicate(:gt?) do |num, input|
|
84
|
+
input > num
|
85
|
+
end
|
86
|
+
|
87
|
+
predicate(:lteq?) do |num, input|
|
88
|
+
!self[:gt?].(num, input)
|
89
|
+
end
|
90
|
+
|
91
|
+
predicate(:gteq?) do |num, input|
|
92
|
+
!self[:lt?].(num, input)
|
93
|
+
end
|
94
|
+
|
95
|
+
predicate(:size?) do |size, input|
|
96
|
+
case size
|
97
|
+
when Fixnum then size == input.size
|
98
|
+
when Range, Array then size.include?(input.size)
|
99
|
+
else
|
100
|
+
raise ArgumentError, "+#{size}+ is not supported type for size? predicate"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
predicate(:min_size?) do |num, input|
|
105
|
+
input.size >= num
|
106
|
+
end
|
107
|
+
|
108
|
+
predicate(:max_size?) do |num, input|
|
109
|
+
input.size <= num
|
110
|
+
end
|
111
|
+
|
112
|
+
predicate(:inclusion?) do |list, input|
|
113
|
+
list.include?(input)
|
114
|
+
end
|
115
|
+
|
116
|
+
predicate(:exclusion?) do |list, input|
|
117
|
+
!self[:inclusion?].(list, input)
|
118
|
+
end
|
119
|
+
|
120
|
+
predicate(:eql?) do |left, right|
|
121
|
+
left.eql?(right)
|
122
|
+
end
|
123
|
+
|
124
|
+
predicate(:format?) do |regex, input|
|
125
|
+
!regex.match(input).nil?
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
module Dry
|
2
|
+
module Logic
|
3
|
+
def self.Result(input, value, rule)
|
4
|
+
case value
|
5
|
+
when Result then value.class.new(value.input, value.success?, rule)
|
6
|
+
when Array then Result::Set.new(input, value, rule)
|
7
|
+
else Result::Value.new(input, value, rule)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class Result
|
12
|
+
include Dry::Equalizer(:success?, :input, :rule)
|
13
|
+
|
14
|
+
attr_reader :input, :value, :rule, :name
|
15
|
+
|
16
|
+
class Result::Set < Result
|
17
|
+
def success?
|
18
|
+
value.all?(&:success?)
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_ary
|
22
|
+
indices = value.map { |v| v.failure? ? value.index(v) : nil }.compact
|
23
|
+
[:input, [rule.name, input, value.values_at(*indices).map(&:to_ary)]]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class Result::Value < Result
|
28
|
+
def to_ary
|
29
|
+
[:input, [rule.name, input, [rule.to_ary]]]
|
30
|
+
end
|
31
|
+
alias_method :to_a, :to_ary
|
32
|
+
end
|
33
|
+
|
34
|
+
class Result::Verified < Result
|
35
|
+
attr_reader :predicate_id
|
36
|
+
|
37
|
+
def initialize(result, predicate_id)
|
38
|
+
@input = result.input
|
39
|
+
@value = result.value
|
40
|
+
@rule = result.rule
|
41
|
+
@name = result.name
|
42
|
+
@predicate_id = predicate_id
|
43
|
+
end
|
44
|
+
|
45
|
+
def call
|
46
|
+
Logic.Result(input, success?, rule)
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_ary
|
50
|
+
[:input, [name, input, [rule.to_ary]]]
|
51
|
+
end
|
52
|
+
alias_method :to_a, :to_ary
|
53
|
+
|
54
|
+
def success?
|
55
|
+
rule.predicate_id == predicate_id
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def initialize(input, value, rule)
|
60
|
+
@input = input
|
61
|
+
@value = value
|
62
|
+
@rule = rule
|
63
|
+
@name = rule.name
|
64
|
+
end
|
65
|
+
|
66
|
+
def call
|
67
|
+
self
|
68
|
+
end
|
69
|
+
|
70
|
+
def curry(predicate_id = nil)
|
71
|
+
if predicate_id
|
72
|
+
Result::Verified.new(self, predicate_id)
|
73
|
+
else
|
74
|
+
self
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def negated
|
79
|
+
self.class.new(input, !value, rule)
|
80
|
+
end
|
81
|
+
|
82
|
+
def >(other)
|
83
|
+
if success?
|
84
|
+
other.(input)
|
85
|
+
else
|
86
|
+
Logic.Result(input, true, rule)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def and(other)
|
91
|
+
if success?
|
92
|
+
other.(input)
|
93
|
+
else
|
94
|
+
self
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def or(other)
|
99
|
+
if success?
|
100
|
+
self
|
101
|
+
else
|
102
|
+
other.(input)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def xor(other)
|
107
|
+
Logic.Result(input, success? ^ other.(input).success?, rule)
|
108
|
+
end
|
109
|
+
|
110
|
+
def success?
|
111
|
+
@value
|
112
|
+
end
|
113
|
+
|
114
|
+
def failure?
|
115
|
+
! success?
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|