logicality 1.0.5 → 2.0.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: 7edc9358a6d67553428d41c02f336e25dd7a9763
4
- data.tar.gz: 1e66c111450fba24d0b0fb3d2e680c6d8ca63cdf
2
+ SHA256:
3
+ metadata.gz: 9c095a928ca7ca83e2ac40bdbbe85569bf66475d78deea2aa48e3b78400aa71a
4
+ data.tar.gz: 131023ffc29713d3f48a57c9ba8422066872289c646cc06d7ce494ecebbc68aa
5
5
  SHA512:
6
- metadata.gz: 402fab8bc9d1889cf311f2d9455f558f7fe2a4b6e4d4b9735277f2fe228350cb4aee5a593f8445c18ca8ef4a6884ab4481c1237f690f7521cf097fb616ccc8b5
7
- data.tar.gz: bd27b379426d0cda3db948eeb01e458a9867f9dade37c1e8c80941806f891ca935b8b3a3ca8fb0a6605e214bda995896f41491e2499ffa85418965ce6a00293a
6
+ metadata.gz: 1230714c64c4756c0eb2e312502b322cb0466b97ee293a09306a2f5d43347857c69a27d2d19fa1b3abf40f4a86dc9099d022af498eced1f3aa1d99853a5cd98f
7
+ data.tar.gz: f4c7b55eb37bbcf67a4415f327bafc91802ead3ad4a07a39be1c1682b41e685b64f98a2d3983d6eb8145ab96097e7b1ac7edb77c62807392e8b34694d51f3619
data/.gitignore CHANGED
@@ -1,2 +1,4 @@
1
1
  .DS_Store
2
2
  *.gem
3
+ /tmp
4
+ /coverage
data/.rubocop.yml CHANGED
@@ -2,3 +2,9 @@ inherit_from: .rubocop_todo.yml
2
2
 
3
3
  Metrics/LineLength:
4
4
  Max: 100
5
+
6
+ Metrics/BlockLength:
7
+ ExcludedMethods: ['it', 'describe', 'context', 'let', 'specify']
8
+
9
+ AllCops:
10
+ TargetRubyVersion: 2.3
data/.rubocop_todo.yml CHANGED
@@ -25,10 +25,10 @@ Metrics/MethodLength:
25
25
  Style/DoubleNegation:
26
26
  Exclude:
27
27
  - 'lib/logicality/interpreter/simple_interpreter.rb'
28
- - 'lib/logicality/logic.rb'
28
+ - 'lib/logicality/logicality.rb'
29
29
 
30
30
  # Offense count: 1
31
31
  # Cop supports --auto-correct.
32
32
  Style/OrAssignment:
33
33
  Exclude:
34
- - 'lib/logicality/logic.rb'
34
+ - 'lib/logicality/logicality.rb'
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.3.7
1
+ 2.6.0
data/.travis.yml CHANGED
@@ -1,8 +1,20 @@
1
+ env:
2
+ global:
3
+ - CC_TEST_REPORTER_ID=20e69ab96711ba4fbc9e0ddce90bc3fc33cd5b110194aa778ed1ec227b597f09
1
4
  language: ruby
2
5
  rvm:
3
- - 2.3.1
4
- - 2.3.7
6
+ # Build on the latest stable of all supported Rubies (https://www.ruby-lang.org/en/downloads/):
7
+ - 2.3.8
8
+ - 2.4.5
9
+ - 2.5.3
10
+ - 2.6.0
5
11
  cache: bundler
12
+ before_script:
13
+ - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
14
+ - chmod +x ./cc-test-reporter
15
+ - ./cc-test-reporter before-build
6
16
  script:
7
17
  - bundle exec rubocop
8
18
  - bundle exec rspec
19
+ after_script:
20
+ - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
data/CHANGELOG.md ADDED
@@ -0,0 +1,10 @@
1
+ # 2.0.0 (January 30th, 2019)
2
+
3
+ Maintenance Release + Top-Level API Change
4
+
5
+ * Added bin/console script
6
+ * Added CHANGELOG
7
+ * Updated README with publication steps, additional testing steps
8
+ * Bumped minimum Ruby to 2.3.8
9
+ * Added Guard
10
+ * Changed Logicality::Logic#evaluate to Logicality#evaluate (breaking change)
data/Gemfile.lock CHANGED
@@ -1,19 +1,56 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- logicality (1.0.5)
4
+ logicality (2.0.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
+ ansi (1.5.0)
9
10
  ast (2.4.0)
11
+ coderay (1.1.2)
10
12
  diff-lcs (1.3)
11
- jaro_winkler (1.5.1)
12
- parallel (1.12.1)
13
- parser (2.5.1.2)
13
+ docile (1.3.1)
14
+ ffi (1.10.0)
15
+ formatador (0.2.5)
16
+ guard (2.15.0)
17
+ formatador (>= 0.2.4)
18
+ listen (>= 2.7, < 4.0)
19
+ lumberjack (>= 1.0.12, < 2.0)
20
+ nenv (~> 0.1)
21
+ notiffany (~> 0.0)
22
+ pry (>= 0.9.12)
23
+ shellany (~> 0.0)
24
+ thor (>= 0.18.1)
25
+ guard-compat (1.2.1)
26
+ guard-rspec (4.7.3)
27
+ guard (~> 2.1)
28
+ guard-compat (~> 1.1)
29
+ rspec (>= 2.99.0, < 4.0)
30
+ hirb (0.7.3)
31
+ jaro_winkler (1.5.2)
32
+ json (2.1.0)
33
+ listen (3.1.5)
34
+ rb-fsevent (~> 0.9, >= 0.9.4)
35
+ rb-inotify (~> 0.9, >= 0.9.7)
36
+ ruby_dep (~> 1.2)
37
+ lumberjack (1.0.13)
38
+ method_source (0.9.2)
39
+ nenv (0.3.0)
40
+ notiffany (0.1.1)
41
+ nenv (~> 0.1)
42
+ shellany (~> 0.0)
43
+ parallel (1.13.0)
44
+ parser (2.6.0.0)
14
45
  ast (~> 2.4.0)
15
46
  powerpack (0.1.2)
47
+ pry (0.12.2)
48
+ coderay (~> 1.1.0)
49
+ method_source (~> 0.9.0)
16
50
  rainbow (3.0.0)
51
+ rb-fsevent (0.10.3)
52
+ rb-inotify (0.10.0)
53
+ ffi (~> 1.0)
17
54
  rspec (3.8.0)
18
55
  rspec-core (~> 3.8.0)
19
56
  rspec-expectations (~> 3.8.0)
@@ -27,24 +64,39 @@ GEM
27
64
  diff-lcs (>= 1.2.0, < 2.0)
28
65
  rspec-support (~> 3.8.0)
29
66
  rspec-support (3.8.0)
30
- rubocop (0.59.2)
67
+ rubocop (0.63.1)
31
68
  jaro_winkler (~> 1.5.1)
32
69
  parallel (~> 1.10)
33
70
  parser (>= 2.5, != 2.5.1.1)
34
71
  powerpack (~> 0.1)
35
72
  rainbow (>= 2.2.2, < 4.0)
36
73
  ruby-progressbar (~> 1.7)
37
- unicode-display_width (~> 1.0, >= 1.0.1)
74
+ unicode-display_width (~> 1.4.0)
38
75
  ruby-progressbar (1.10.0)
39
- unicode-display_width (1.4.0)
76
+ ruby_dep (1.5.0)
77
+ shellany (0.0.1)
78
+ simplecov (0.16.1)
79
+ docile (~> 1.1)
80
+ json (>= 1.8, < 3)
81
+ simplecov-html (~> 0.10.0)
82
+ simplecov-console (0.4.2)
83
+ ansi
84
+ hirb
85
+ simplecov
86
+ simplecov-html (0.10.2)
87
+ thor (0.20.3)
88
+ unicode-display_width (1.4.1)
40
89
 
41
90
  PLATFORMS
42
91
  ruby
43
92
 
44
93
  DEPENDENCIES
94
+ guard-rspec (~> 4.7)
45
95
  logicality!
46
96
  rspec
47
- rubocop (~> 0.59.2)
97
+ rubocop (~> 0.63.1)
98
+ simplecov (~> 0.16.1)
99
+ simplecov-console (~> 0.4.2)
48
100
 
49
101
  BUNDLED WITH
50
- 1.16.3
102
+ 1.17.2
data/Guardfile ADDED
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ guard :rspec, cmd: 'bundle exec rspec' do
4
+ require 'guard/rspec/dsl'
5
+ dsl = Guard::RSpec::Dsl.new(self)
6
+
7
+ # RSpec files
8
+ rspec = dsl.rspec
9
+ watch(rspec.spec_helper) { rspec.spec_dir }
10
+ watch(rspec.spec_support) { rspec.spec_dir }
11
+ watch(rspec.spec_files)
12
+
13
+ # Ruby files
14
+ ruby = dsl.ruby
15
+ dsl.watch_spec_files_for(ruby.lib_files)
16
+ end
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Logicality
4
4
 
5
- [![Build Status](https://travis-ci.org/bluemarblepayroll/logicality-rb.svg?branch=master)](https://travis-ci.org/bluemarblepayroll/logicality-rb)
5
+ [![Gem Version](https://badge.fury.io/rb/logicality.svg)](https://badge.fury.io/rb/logicality) [![Build Status](https://travis-ci.org/bluemarblepayroll/logicality-rb.svg?branch=master)](https://travis-ci.org/bluemarblepayroll/logicality-rb) [![Maintainability](https://api.codeclimate.com/v1/badges/c5ed72e2a272ca34b3ce/maintainability)](https://codeclimate.com/github/bluemarblepayroll/logicality-rb/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/c5ed72e2a272ca34b3ce/test_coverage)](https://codeclimate.com/github/bluemarblepayroll/logicality-rb/test_coverage) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
6
 
7
7
  A common problem that many frameworks have is the ability to give developers an expressive
8
8
  intermediary scripting language or DSL. Logicality helps solve this problem by providing a simple
@@ -19,7 +19,7 @@ resolving boolean values such as:
19
19
 
20
20
  ## Credit
21
21
 
22
- Deep inspiration was taken from [this set of articles](https://ruslanspivak.com/lsbasi-part7/).
22
+ Deep inspiration was taken from [this set of articles](https://ruslanspivak.com/lsbasi-part7/).
23
23
  Here, the author gives details around the theory and practical implementation of creating a basic
24
24
  language processor and compiler.
25
25
 
@@ -51,7 +51,7 @@ Now you can bind and evaluate this expression against passed in objects:
51
51
 
52
52
  ````
53
53
  record = { 'visible' => false, 'admin' => true }
54
- visible = Logicality::Logic.evaluate('visible || admin', record) # resolves to true.
54
+ visible = Logicality.evaluate('visible || admin', record) # resolves to true.
55
55
  ````
56
56
 
57
57
  ### Plugging in a Custom Resolver
@@ -65,7 +65,7 @@ resolver = lambda do |value, input|
65
65
  end
66
66
 
67
67
  record = { visible: false, admin: true }
68
- visible = Logicality::Logic.evaluate('visible || admin', record) # resolves to true.
68
+ visible = Logicality.evaluate('visible || admin', record, resolver) # resolves to true.
69
69
  ````
70
70
 
71
71
  ## Contributing
@@ -85,9 +85,37 @@ Basic steps to take to get this repository compiling:
85
85
  To execute the test suite run:
86
86
 
87
87
  ````
88
- rspec
88
+ bundle exec rspec spec --format documentation
89
89
  ````
90
90
 
91
+ Alternatively, you can have Guard watch for changes:
92
+
93
+ ````
94
+ bundle exec guard
95
+ ````
96
+
97
+ Also, do not forget to run Rubocop:
98
+
99
+ ````
100
+ bundle exec rubocop
101
+ ````
102
+
103
+ ### Publishing
104
+
105
+ Note: ensure you have proper authorization before trying to publish new versions.
106
+
107
+ After code changes have successfully gone through the Pull Request review process then the following steps should be followed for publishing new versions:
108
+
109
+ 1. Merge Pull Request into master
110
+ 2. Update ```lib/logicality/version.rb``` using [semantic versioning](https://semver.org/)
111
+ 3. Install dependencies: ```bundle```
112
+ 4. Update ```CHANGELOG.md``` with release notes
113
+ 5. Commit & push master to remote and ensure CI builds master successfully
114
+ 6. Build the project locally: `gem build logicality`
115
+ 7. Publish package to RubyGems: `gem push logicality-X.gem` where X is the version to push
116
+ 8. Tag master with new version: `git tag <version>`
117
+ 9. Push tags remotely: `git push origin --tags`
118
+
91
119
  ## License
92
120
 
93
121
  This project is MIT Licensed.
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'logicality'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start
@@ -11,12 +11,12 @@ module Logicality
11
11
  module Lexer
12
12
  # Define the main regular expression matchers used by the lexer.
13
13
  module Grammar
14
- VALUE = /([a-zA-Z0-9_$@?\.]+)/
15
- AND_OP = /(&&)/
16
- OR_OP = /(\|\|)/
17
- NOT_OP = /(\!)/
18
- LEFT_PAREN = /(\()/
19
- RIGHT_PAREN = /(\))/
14
+ VALUE = /([a-zA-Z0-9_$@?\.]+)/.freeze
15
+ AND_OP = /(&&)/.freeze
16
+ OR_OP = /(\|\|)/.freeze
17
+ NOT_OP = /(\!)/.freeze
18
+ LEFT_PAREN = /(\()/.freeze
19
+ RIGHT_PAREN = /(\))/.freeze
20
20
  end
21
21
  end
22
22
  end
@@ -10,4 +10,57 @@
10
10
  require_relative 'lexer/lexer'
11
11
  require_relative 'parser/parser'
12
12
  require_relative 'interpreter/interpreter'
13
- require_relative 'logic'
13
+
14
+ # Module that defines the main class-level API for this library.
15
+ module Logicality
16
+ class << self
17
+ def evaluate(expression, input = nil, resolver = nil)
18
+ node = get(expression)
19
+ wrapper = resolver_wrapper(input, resolver)
20
+ interpreter = Interpreter::SimpleInterpreter.new(wrapper)
21
+
22
+ interpreter.visit(node)
23
+ end
24
+
25
+ private
26
+
27
+ def resolver_wrapper(input, resolver)
28
+ if resolver
29
+ ->(value) { resolver.call(value, input) }
30
+ else
31
+ ->(value) { object_resolver.call(value, input) }
32
+ end
33
+ end
34
+
35
+ def object_resolver
36
+ lambda do |value, input|
37
+ return false unless input
38
+
39
+ if input.respond_to?(value)
40
+ !!input.send(value)
41
+ elsif input.respond_to?(:[])
42
+ !!input[value]
43
+ else
44
+ false
45
+ end
46
+ end
47
+ end
48
+
49
+ def cache
50
+ @cache ||= {}
51
+ end
52
+
53
+ def set(expression, node)
54
+ cache[expression] ||= node
55
+ end
56
+
57
+ def get(expression)
58
+ return cache[expression] if cache[expression]
59
+
60
+ lexer = Lexer::RegexpLexer.new(expression)
61
+ parser = Parser::SimpleParser.new(lexer)
62
+
63
+ set(expression, parser.parse)
64
+ end
65
+ end
66
+ end
@@ -8,5 +8,5 @@
8
8
  #
9
9
 
10
10
  module Logicality
11
- VERSION = '1.0.5'
11
+ VERSION = '2.0.0'
12
12
  end
data/logicality.gemspec CHANGED
@@ -22,8 +22,11 @@ Gem::Specification.new do |s|
22
22
  s.homepage = 'https://github.com/bluemarblepayroll/logicality-rb'
23
23
  s.license = 'MIT'
24
24
 
25
- s.required_ruby_version = '>= 2.3.1'
25
+ s.required_ruby_version = '>= 2.3.8'
26
26
 
27
+ s.add_development_dependency('guard-rspec', '~>4.7')
27
28
  s.add_development_dependency('rspec')
28
- s.add_development_dependency('rubocop', '~> 0.59.2')
29
+ s.add_development_dependency('rubocop', '~>0.63.1')
30
+ s.add_development_dependency('simplecov', '~>0.16.1')
31
+ s.add_development_dependency('simplecov-console', '~>0.4.2')
29
32
  end
@@ -7,13 +7,13 @@
7
7
  # LICENSE file in the root directory of this source tree.
8
8
  #
9
9
 
10
- require './lib/logicality'
10
+ require './spec/spec_helper'
11
11
 
12
12
  def run(tests)
13
13
  tests.each do |x|
14
14
  input = x[1] ? x[1].map { |k, v| [k.to_s, v] }.to_h : nil
15
15
 
16
- result = Logicality::Logic.evaluate(x[0], input)
16
+ result = Logicality.evaluate(x[0], input)
17
17
 
18
18
  expect(result).to eq(x[2]), "Failed: #{x[0]} (input: #{input}): expected #{x[2]} got: #{result}"
19
19
  end
@@ -21,7 +21,7 @@ def run(tests)
21
21
  nil
22
22
  end
23
23
 
24
- describe Logicality::Logic do
24
+ describe Logicality do
25
25
  context 'when evaluating' do
26
26
  it 'should evaluate boolean-only expressions' do
27
27
  tests = [
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2018-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ require 'simplecov'
11
+ require 'simplecov-console'
12
+
13
+ SimpleCov.formatter = SimpleCov::Formatter::Console
14
+ SimpleCov.start
15
+
16
+ require './lib/logicality'
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logicality
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.5
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew Ruggio
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-09-28 00:00:00.000000000 Z
11
+ date: 2019-02-05 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: guard-rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4.7'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: rspec
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -30,14 +44,42 @@ dependencies:
30
44
  requirements:
31
45
  - - "~>"
32
46
  - !ruby/object:Gem::Version
33
- version: 0.59.2
47
+ version: 0.63.1
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.63.1
55
+ - !ruby/object:Gem::Dependency
56
+ name: simplecov
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.16.1
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.16.1
69
+ - !ruby/object:Gem::Dependency
70
+ name: simplecov-console
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.4.2
34
76
  type: :development
35
77
  prerelease: false
36
78
  version_requirements: !ruby/object:Gem::Requirement
37
79
  requirements:
38
80
  - - "~>"
39
81
  - !ruby/object:Gem::Version
40
- version: 0.59.2
82
+ version: 0.4.2
41
83
  description: |2
42
84
  A common problem that many frameworks have is the ability to give developers
43
85
  an expressive intermediary scripting language or DSL.
@@ -45,7 +87,8 @@ description: |2
45
87
  expression evaluator.
46
88
  email:
47
89
  - mruggio@bluemarblepayroll.com
48
- executables: []
90
+ executables:
91
+ - console
49
92
  extensions: []
50
93
  extra_rdoc_files: []
51
94
  files:
@@ -55,10 +98,13 @@ files:
55
98
  - ".rubocop_todo.yml"
56
99
  - ".ruby-version"
57
100
  - ".travis.yml"
101
+ - CHANGELOG.md
58
102
  - Gemfile
59
103
  - Gemfile.lock
104
+ - Guardfile
60
105
  - LICENSE
61
106
  - README.md
107
+ - bin/console
62
108
  - lib/logicality.rb
63
109
  - lib/logicality/interpreter/interpreter.rb
64
110
  - lib/logicality/interpreter/node_visitor.rb
@@ -67,7 +113,6 @@ files:
67
113
  - lib/logicality/lexer/lexer.rb
68
114
  - lib/logicality/lexer/regexp_lexer.rb
69
115
  - lib/logicality/lexer/token.rb
70
- - lib/logicality/logic.rb
71
116
  - lib/logicality/logicality.rb
72
117
  - lib/logicality/parser/ast/ast.rb
73
118
  - lib/logicality/parser/ast/binary_operator_node.rb
@@ -78,7 +123,8 @@ files:
78
123
  - lib/logicality/parser/simple_parser.rb
79
124
  - lib/logicality/version.rb
80
125
  - logicality.gemspec
81
- - spec/logic_spec.rb
126
+ - spec/logicality_spec.rb
127
+ - spec/spec_helper.rb
82
128
  homepage: https://github.com/bluemarblepayroll/logicality-rb
83
129
  licenses:
84
130
  - MIT
@@ -91,17 +137,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
91
137
  requirements:
92
138
  - - ">="
93
139
  - !ruby/object:Gem::Version
94
- version: 2.3.1
140
+ version: 2.3.8
95
141
  required_rubygems_version: !ruby/object:Gem::Requirement
96
142
  requirements:
97
143
  - - ">="
98
144
  - !ruby/object:Gem::Version
99
145
  version: '0'
100
146
  requirements: []
101
- rubyforge_project:
102
- rubygems_version: 2.5.2.3
147
+ rubygems_version: 3.0.1
103
148
  signing_key:
104
149
  specification_version: 4
105
150
  summary: String-based boolean expression evaluator
106
151
  test_files:
107
- - spec/logic_spec.rb
152
+ - spec/logicality_spec.rb
153
+ - spec/spec_helper.rb
@@ -1,66 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- #
4
- # Copyright (c) 2018-present, Blue Marble Payroll, LLC
5
- #
6
- # This source code is licensed under the MIT license found in the
7
- # LICENSE file in the root directory of this source tree.
8
- #
9
-
10
- module Logicality
11
- # Class that defines the main class-level API for this library.
12
- class Logic
13
- class << self
14
- def evaluate(expression, input = nil, resolver = nil)
15
- node = get(expression)
16
- wrapper = resolver_wrapper(input, resolver)
17
- interpreter = Interpreter::SimpleInterpreter.new(wrapper)
18
-
19
- interpreter.visit(node)
20
- end
21
-
22
- private
23
-
24
- def resolver_wrapper(input, resolver)
25
- if resolver
26
- ->(value) { resolver.call(value, input) }
27
- else
28
- ->(value) { object_resolver.call(value, input) }
29
- end
30
- end
31
-
32
- def object_resolver
33
- lambda do |value, input|
34
- return false unless input
35
-
36
- if input.respond_to?(value)
37
- !!input.send(value)
38
- elsif input.respond_to?(:[])
39
- !!input[value]
40
- else
41
- false
42
- end
43
- end
44
- end
45
-
46
- def cache
47
- @cache || {}
48
- end
49
-
50
- def set(expression, node)
51
- @cache = {} unless @cache
52
-
53
- @cache[expression] = node
54
- end
55
-
56
- def get(expression)
57
- return cache[expression] if cache[expression]
58
-
59
- lexer = Lexer::RegexpLexer.new(expression)
60
- parser = Parser::SimpleParser.new(lexer)
61
-
62
- set(expression, parser.parse)
63
- end
64
- end
65
- end
66
- end