namarara 0.9.4

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a3e1538437882fe2870b7954c6d9d956c3aa99c79f62eca39c625688b76a2056
4
+ data.tar.gz: 3729dba6c1adb99865d166a7690ab7d21fad7be57aae710f6150dc792a6d6e1c
5
+ SHA512:
6
+ metadata.gz: 2e81025ef3050f8a27d87029ff3db0238f08fc081d9d4b8b3510dd09a7a2f26d6fd07a89676addf89f135890eb1991802c0185ae5eeede61db991921f957ff09
7
+ data.tar.gz: 25b30ba9b15aab14afd9c127333134860f428da6778e4aa271649ff46dbefa9f825e2e20cb87fc20bacb6ba2de129b099155ed453ed410213608a3e8483e8ea3
@@ -0,0 +1,33 @@
1
+ ---
2
+ name: Ruby Gem
3
+
4
+ on:
5
+ pull_request:
6
+ branches:
7
+ - master
8
+ push:
9
+ branches:
10
+ - master
11
+
12
+ jobs:
13
+ build:
14
+ name: Build + Publish
15
+ runs-on: ubuntu-latest
16
+
17
+ steps:
18
+ - uses: actions/checkout@master
19
+ - name: Set up Ruby 2.6
20
+ uses: actions/setup-ruby@v1
21
+ with:
22
+ ruby-version: 2.6.x
23
+
24
+ - name: Publish to RubyGems
25
+ run: |
26
+ mkdir -p $HOME/.gem
27
+ touch $HOME/.gem/credentials
28
+ chmod 0600 $HOME/.gem/credentials
29
+ printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
30
+ gem build *.gemspec
31
+ gem push *.gem
32
+ env:
33
+ GEM_HOST_API_KEY: ${{secrets.RUBYGEMS_AUTH_TOKEN}}
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rubocop.yml ADDED
@@ -0,0 +1,58 @@
1
+ require: rubocop-rspec
2
+
3
+ ##
4
+ ## TEMPORARILY disabled
5
+ ##
6
+
7
+ AllCops:
8
+ TargetRubyVersion: 2.5
9
+
10
+ ##
11
+ ## LOCAL PREFERENCES
12
+ ##
13
+ # Allow bigger test cases ('examples')
14
+ RSpec/ExampleLength:
15
+ Enabled: true
16
+ Max: 10
17
+
18
+ Metrics/MethodLength:
19
+ Enabled: true
20
+ Max: 10
21
+
22
+ Metrics/BlockLength:
23
+ Enabled: false
24
+ Exclude:
25
+ - spec/**/*
26
+
27
+ Metrics/AbcSize:
28
+ Enabled: false
29
+
30
+ # Disable errors due to rspec-specific patterns
31
+ RSpec/DescribedClass:
32
+ Enabled: false
33
+
34
+ ##
35
+ ## DISABLE all layout/whitespace-related errors
36
+ ##
37
+
38
+ RSpec/FilePath:
39
+ Enabled: false
40
+
41
+ Style/IfUnlessModifier:
42
+ Enabled: false
43
+
44
+ Style/MultilineIfThen:
45
+ Enabled: false
46
+
47
+ # Style/FileName:
48
+ # Enabled: false
49
+
50
+ # Style/StringLiterals:
51
+ # Enabled: false
52
+
53
+ Style/FormatString:
54
+ Enabled: false
55
+
56
+ Style/Documentation:
57
+ Enabled: false
58
+
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.2.7
data/.tool-versions ADDED
@@ -0,0 +1 @@
1
+ ruby 2.6.1
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.4.1
5
+ before_install: gem install bundler -v 1.15.3
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in namarara.gemspec
6
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Roguelearg
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all 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,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,124 @@
1
+ # Namarara
2
+
3
+ Namarara is a library that can parses boolean expressions, builds an [binary
4
+ expression tree](https://en.wikipedia.org/wiki/Binary_expression_tree) and
5
+ evalutes a result given a set of values associated to the variables used within
6
+ the boolean expression.
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ ```ruby
13
+ gem 'namarara'
14
+ ```
15
+
16
+ And then execute:
17
+
18
+ ```shell-session
19
+ $ bundle
20
+ ```
21
+
22
+ Or install it yourself as:
23
+
24
+ ```shell-session
25
+ $ gem install namarara
26
+ ```
27
+
28
+ ## Usage
29
+
30
+ ### Evaluate a single expression
31
+
32
+ ```ruby
33
+ require 'namarara'
34
+
35
+ # Initialize Namarara
36
+ namarara = Namarara::Parser.new(Namarara::Lexer.new)
37
+
38
+ # Prepare variables
39
+ namarara.names = {
40
+ this: 'true',
41
+ that: 'false',
42
+ other: 'false',
43
+ something_else: 'true'
44
+ }
45
+
46
+ # Build a binary expression tree (aka BET) from string
47
+ # and inject values
48
+ exp_tree = namarara.parse('this AND (that OR other) AND something_else')
49
+
50
+ # Compute tree with variables
51
+ result = exp_tree.compute
52
+ puts result # = false
53
+ ```
54
+
55
+ ### Evaluating a set of rules
56
+
57
+ ```ruby
58
+ require 'namarara'
59
+
60
+ # Initialize Namarara
61
+ namarara = Namarara::Parser.new(Namarara::Lexer.new)
62
+
63
+ # A set of rules i want to check
64
+ # (in this example we are looking for sensitive personnal data)
65
+ rules = {
66
+ vulnerable_person: 'is_adult AND is_subordinate',
67
+ has_constraints: 'is_adult AND has_children',
68
+ is_child: 'NOT is_adult'
69
+ # ...
70
+ }
71
+
72
+ # A set of values i want to inject (values must be expressed as strings)
73
+ namarara.names = {
74
+ "is_adult" => 'false',
75
+ "is_subordinate" => 'true',
76
+ "has_children" => 'true'
77
+ }
78
+
79
+ results = rules.map { |rule, expr| [rule, namarara.parse(expr).compute] }
80
+
81
+ if results.select{ |rule, value| value }.empty?
82
+ puts "Perfect! Nothing to say ;-)"
83
+ else
84
+ puts "Warning: you are collectif sensitive personnal data !"
85
+ results.each do |rule, value|
86
+ puts "#{value ? '>>':' '} #{rule}: #{value}"
87
+ end
88
+ end
89
+ ```
90
+
91
+ ## Development
92
+
93
+ After checking out the repo, run `bin/setup` to install dependencies.
94
+
95
+ Then, run `rake test` to run the tests.
96
+
97
+ You can also run `bin/console` for an interactive prompt that will allow you to experiment.
98
+
99
+ To install this gem onto your local machine, run `bundle exec rake install`.
100
+
101
+ To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
102
+
103
+ ## Contributing
104
+
105
+ Bug reports and pull requests are welcome on GitHub at https://github.com/glenux/namarara
106
+
107
+
108
+ ## License and copyright
109
+
110
+ [Namarara](https://github.com/glenux/namarara) is an open source project under the terms of the [MIT License](http://opensource.org/licenses/MIT).
111
+
112
+ Original author : [Brendon Torre](https://www.linkedin.com/in/brendon-torre-b128a0168)
113
+
114
+ Current developer & maintainer : Glenn Y. Rolland ([@glenux](https://twitter.com/glenux))
115
+
116
+
117
+ ## Sponsors and funding
118
+
119
+ [Namarara](https://github.com/glenux/namarara) is an independent project whose development and maintenance is made possible thanks to the support of its patrons.
120
+
121
+ If you wish to join them and support the work of its author, just participate with this link :
122
+
123
+ __>>> [Become a patron or sponsor on Patreon](https://www.patreon.com/glenux) <<<__
124
+
data/Rakefile ADDED
@@ -0,0 +1,28 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+ require 'rubocop/rake_task'
4
+
5
+ # Add additional test suite definitions to the default test task here
6
+ namespace :spec do
7
+ desc 'Runs RuboCop on specified directories'
8
+ RuboCop::RakeTask.new(:rubocop) do |task|
9
+ # Dirs: app, lib, test
10
+ task.patterns = ['exe/**/*.rb', 'lib/**/*.rb', 'spec/**/*_spec.rb']
11
+
12
+ # Make it easier to disable cops.
13
+ task.options << "--display-cop-names"
14
+
15
+ # Abort on failures (fix your code first)
16
+ task.fail_on_error = true
17
+ end
18
+ end
19
+
20
+ Rake::TestTask.new(:spec) do |t|
21
+ t.libs << "spec"
22
+ t.libs << "lib"
23
+ t.test_files = FileList['spec/**/*_spec.rb']
24
+ end
25
+
26
+ Rake::Task[:spec].enhance ['spec:rubocop']
27
+
28
+ task :default => :spec
data/TODO.md ADDED
@@ -0,0 +1,13 @@
1
+ # TODO
2
+
3
+ * prefixer les spec/files par success ou error
4
+ * factoriser parser dans tous les tests unitaires (le mettre en let(:parser)
5
+ * dans les tests, verifier quelle variables ont été reportées comme non définies
6
+ (si possible)
7
+ * pour priority parser, comparer le to_s de l'expression
8
+ avec celui d'un arbre correct plutot que le résultat
9
+
10
+ * tester une expression pour chaque type possible dans la grammaire de EXPR
11
+ * tester ensuite quelques combinaisons simples
12
+ * tester enfin les cas foireux (ceux des priorités à gauche/droite sur les NOT, etc.)
13
+
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "namarara"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/demo.rb ADDED
@@ -0,0 +1,46 @@
1
+
2
+ $:.insert(0, 'lib')
3
+ require 'namarara'
4
+
5
+ def verify_input
6
+ parser = Namarara::Parser.new(Namarara::Lexer.new)
7
+
8
+ # on démarre avec zéro alertes
9
+ warnings = []
10
+
11
+ # ma liste de regles pour lesquelles je veux des alertes
12
+ rules = [
13
+ 'est_adulte AND est_subordone',
14
+ 'est_adulte AND a_des_enfants',
15
+ 'NOT est_adulte'
16
+ # ...
17
+ ]
18
+
19
+ # contexte récupéré en HTTP ou en base de données
20
+ context = {
21
+ "est_adulte" => 'false',
22
+ "est_subordone" => 'true',
23
+ "a_des_enfants" => 'true'
24
+ # 80 valeurs de plus si on veut
25
+ }
26
+
27
+ rules.each do |rule|
28
+ parser.names = context
29
+ token = parser.parse(rule)
30
+ res = token.compute
31
+ if res then
32
+ warnings << "La règle #{rule} n'est pas respectée"
33
+ end
34
+ end
35
+
36
+ if not warnings.empty?
37
+ puts "Attention: vous collectez des DCP de personnes vulnerables"
38
+ puts warnings.join("\n")
39
+ else
40
+ puts "Rien à dire :-)"
41
+ end
42
+
43
+ end
44
+
45
+ verify_input()
46
+
data/exe/namarara-api ADDED
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.insert(0, 'lib')
4
+
5
+ require 'namarara'
6
+ require 'json'
7
+ require 'sinatra'
8
+
9
+ get '/' do
10
+ <<-EOF
11
+ Bonjour le monde !
12
+ EOF
13
+ end
14
+
15
+ post '/single' do
16
+ json = JSON.parse(request.body.read)
17
+ expr = json['expr'] || ''
18
+ vars = json['vars'] || ''
19
+ puts json.inspect
20
+ result = Namarara.parse_string(expr, vars, true)
21
+ JSON.generate(result)
22
+ end
23
+
data/exe/namarara-cli ADDED
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.insert(0, 'lib')
4
+
5
+ require 'thor'
6
+ require 'rly'
7
+ require 'namarara'
8
+ require 'json'
9
+
10
+ module Namarara
11
+ class ParseCli < Thor
12
+ class_option :debug,
13
+ type: :boolean,
14
+ aliases: '-d',
15
+ default: false,
16
+ desc: "Enable debugging output"
17
+ class_option :format,
18
+ type: :string,
19
+ aliases: '-f',
20
+ default: 'text',
21
+ enum: ['text','json'],
22
+ desc: "Output format"
23
+
24
+ desc 'file FILE VARS',
25
+ 'Parse FILE into tokens then compute with VARS'
26
+ def file(infile, *vars)
27
+ line = File.read(infile).gsub(/\n/,'')
28
+ vars_hash = get_vars_hash(vars)
29
+ res = parse_string(line, vars_hash, options[:debug])
30
+ puts format(res, options[:format])
31
+ end
32
+
33
+ desc 'string STRING VARS',
34
+ 'Parse STRING into tokens then compute with VARS'
35
+ def string(line, *vars)
36
+ vars_hash = get_vars_hash(vars)
37
+ res = parse_string(line, vars_hash, options[:debug])
38
+ puts format(res, options[:format])
39
+ end
40
+
41
+ private
42
+
43
+ # Convert VAR=value list into hash
44
+ def get_vars_hash(vars)
45
+ tab_vars = {}
46
+ vars.each do |var|
47
+ tab_vars[var.split('=')[0]] = var.split('=')[1]
48
+ end
49
+ tab_vars
50
+ end
51
+
52
+ def format(result, format)
53
+ case format
54
+ when 'text' then
55
+ txt = []
56
+ txt << "EXPR: #{result[:expr]}"
57
+ txt << "TREE: #{result[:tree]}"
58
+ result[:errors].each do |error|
59
+ txt << "ERROR: #{error}"
60
+ end
61
+ txt << "RESULT: #{result[:result]}"
62
+ txt.join("\n")
63
+ when 'json'
64
+ JSON.generate(result)
65
+ else
66
+ raise 'Unknown output format'
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ Namarara::ParseCli.start(ARGV)
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Namarara
4
+ module Errors
5
+ class InvalidGrammar < EvalError
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Namarara
4
+ module Errors
5
+ class VarNotDefined < EvalError
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Namarara
4
+ class EvalError
5
+ attr_accessor :var
6
+ attr_accessor :message
7
+
8
+ def initialize(hash)
9
+ # validate input
10
+ raise ArgumentError unless hash[:message]
11
+
12
+ # load input
13
+ @message = hash[:message]
14
+ @var = hash[:var]
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Namarara
4
+ class Lexer < Rly::Lex
5
+ attr_reader :logger
6
+
7
+ ignore "\t\n "
8
+
9
+ # token :SPACE, /\s+/
10
+ token :L_PAR, /\(/
11
+ token :R_PAR, /\)/
12
+ token :NUMBER, /[0-9]+(\.[0-9]+)?/
13
+ token :STRING, /"([^"]*)"/ do |s|
14
+ s.value.gsub!(/"(.*)"/, '\1')
15
+ s
16
+ end
17
+
18
+ token :EQ_OP, /\=/
19
+ token :T_BOOL, /true/i
20
+ token :F_BOOL, /false/i
21
+ token :VAR, /[a-z][a-zA-Z0-9_]+/
22
+ token :AND_OP, /AND/
23
+ token :OR_OP, /OR/
24
+ token :NOT_OP, /NOT/
25
+
26
+ def initialize(logger = nil)
27
+ @logger = logger
28
+ super()
29
+ end
30
+
31
+ on_error do |t|
32
+ t.lexer.logger&.error "Illegal character #{t.value}"
33
+ t.lexer.pos += 1
34
+ nil
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,297 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Namarara
4
+ class TreeExpr
5
+ def compute
6
+ raise NotImplementedError
7
+ end
8
+ end
9
+
10
+ class TreeValue
11
+ attr_reader :value
12
+
13
+ def to_s
14
+ raise NotImplementedError
15
+ end
16
+ end
17
+
18
+ class VarValue < TreeValue
19
+ attr_reader :errors
20
+
21
+ def initialize(str, value)
22
+ @errors = []
23
+ @name = str
24
+ @value = value
25
+ @value = true if value =~ /^true$/i
26
+ @value = false if value =~ /^false$/i
27
+ return unless @value.nil?
28
+
29
+ @errors << Errors::VarNotDefined.new(
30
+ message: "No value for #{@name}",
31
+ var: @name
32
+ )
33
+ end
34
+
35
+ def compute
36
+ @value
37
+ end
38
+
39
+ def to_s
40
+ "var:#{@name}<-(#{@value})"
41
+ end
42
+ end
43
+
44
+ class NumberValue < TreeValue
45
+ attr_reader :errors
46
+
47
+ def initialize(str)
48
+ @errors = []
49
+ @value = str
50
+ end
51
+
52
+ def compute
53
+ @value
54
+ end
55
+
56
+ def to_s
57
+ "number:#{@value}"
58
+ end
59
+ end
60
+
61
+ class StringValue < TreeValue
62
+ attr_reader :errors
63
+
64
+ def initialize(str)
65
+ @errors = []
66
+ @value = str
67
+ end
68
+
69
+ def compute
70
+ @value
71
+ end
72
+
73
+ def to_s
74
+ "string:\"#{@value}\""
75
+ end
76
+ end
77
+
78
+ class BoolValue < TreeValue
79
+ attr_reader :errors
80
+
81
+ def initialize(str)
82
+ @errors = []
83
+ @value = case str
84
+ when /true/i then true
85
+ when /false/i then false
86
+ end
87
+ end
88
+
89
+ def compute
90
+ @value
91
+ end
92
+
93
+ def to_s
94
+ "bool:#{@value}"
95
+ end
96
+ end
97
+
98
+ class AndOp < TreeExpr
99
+ attr_reader :errors
100
+
101
+ def initialize(lval, rval)
102
+ @errors = []
103
+ @errors.concat lval.errors
104
+ @errors.concat rval.errors
105
+ @lval = lval
106
+ @rval = rval
107
+ end
108
+
109
+ def compute
110
+ # rubocop:disable Style/DoubleNegation
111
+ !!@lval.compute && !!@rval.compute
112
+ # rubocop:enable Style/DoubleNegation
113
+ end
114
+
115
+ def to_s
116
+ "( #{@lval} ) AND ( #{@rval} )"
117
+ end
118
+ end
119
+
120
+ class OrOp
121
+ attr_reader :errors
122
+
123
+ def initialize(lval, rval)
124
+ @errors = []
125
+ @errors.concat lval.errors
126
+ @errors.concat rval.errors
127
+ @lval = lval
128
+ @rval = rval
129
+ end
130
+
131
+ def compute
132
+ # rubocop:disable Style/DoubleNegation
133
+ !!@lval.compute || !!@rval.compute
134
+ # rubocop:enable Style/DoubleNegation
135
+ end
136
+
137
+ def to_s
138
+ "( #{@lval} ) OR ( #{@rval} )"
139
+ end
140
+ end
141
+
142
+ class NotOp
143
+ attr_reader :errors
144
+
145
+ def initialize(expr)
146
+ @errors = []
147
+ @errors.concat expr.errors
148
+ @expr = expr
149
+ end
150
+
151
+ def compute
152
+ !@expr.compute
153
+ end
154
+
155
+ def to_s
156
+ "NOT ( #{@expr} )"
157
+ end
158
+ end
159
+
160
+ class EqOp
161
+ attr_reader :errors
162
+
163
+ def initialize(lval, rval)
164
+ @errors = []
165
+ @errors.concat lval.errors
166
+ @errors.concat rval.errors
167
+ @lval = lval
168
+ @rval = rval
169
+ end
170
+
171
+ def compute
172
+ @lval.value == @rval.value
173
+ end
174
+
175
+ def to_s
176
+ "#{@lval} = #{@rval}"
177
+ end
178
+ end
179
+
180
+ # Cut HERE
181
+ # 8< ---- 8< ---- ...
182
+
183
+ class Parser < Rly::Yacc
184
+ class MissingNamesError < RuntimeError; end
185
+ attr_writer :names
186
+
187
+ # Initialize names hash
188
+ def initialize(*args)
189
+ @names = nil
190
+ super(*args)
191
+ end
192
+
193
+ # Make sure names are filled in
194
+ def parse(str)
195
+ raise MissingNamesError if @names.nil?
196
+
197
+ super(str)
198
+ end
199
+
200
+ # Check if grammar is valid
201
+ def check_grammar(line, tokens)
202
+ grammar = tokens.to_s.split(/=|AND|OR/)
203
+ expr = line.split(/=|AND|OR/)
204
+ return if grammar.size == expr.size
205
+ return if grammar.empty?
206
+
207
+ tokens.errors << Errors::InvalidGrammar.new(
208
+ message: 'Invalid Grammar'
209
+ )
210
+ end
211
+
212
+ precedence :left, :VAR
213
+ precedence :left, :OR_OP
214
+ precedence :left, :AND_OP
215
+ precedence :left, :EQ_OP
216
+ precedence :right, :L_PAR, :R_PAR
217
+ precedence :right, :UMINUS
218
+
219
+ rule 'statement : expr' do |st, e|
220
+ st.value = e.value
221
+ end
222
+
223
+ rule 'bool_expr : F_BOOL' do |ex, l|
224
+ ex.value = l.value
225
+ end
226
+
227
+ rule 'bool_expr : T_BOOL' do |ex, l|
228
+ ex.value = l.value
229
+ end
230
+
231
+ rule 'expr : VAR' do |ex, l|
232
+ ex.value = VarValue.new(l.value.to_s, @names[l.value.to_s])
233
+ end
234
+
235
+ rule 'expr : bool_expr' do |ex, l|
236
+ ex.value = BoolValue.new(l.value)
237
+ end
238
+
239
+ rule 'expr : STRING' do |ex, l|
240
+ ex.value = StringValue.new(l.value)
241
+ end
242
+
243
+ rule 'expr : NUMBER' do |ex, l|
244
+ ex.value = NumberValue.new(l.value)
245
+ end
246
+
247
+ rule 'expr : expr OR_OP expr' do |ex, l, _e, r|
248
+ ex.value = OrOp.new(
249
+ l.value,
250
+ r.value
251
+ )
252
+ end
253
+
254
+ rule 'expr : expr AND_OP expr' do |ex, l, _e, r|
255
+ ex.value = AndOp.new(
256
+ l.value,
257
+ r.value
258
+ )
259
+ end
260
+
261
+ rule 'expr : expr EQ_OP expr' do |ex, v, _eq, n|
262
+ ex.value = EqOp.new(
263
+ v.value,
264
+ n.value
265
+ )
266
+ end
267
+
268
+ rule 'expr : L_PAR expr R_PAR' do |ex, _l, e, _r|
269
+ ex.value = e.value
270
+ end
271
+
272
+ rule 'expr : NOT_OP expr %prec UMINUS' do |ex, _l, e|
273
+ ex.value = NotOp.new(e.value)
274
+ end
275
+
276
+ # rule 'expr : VAR EQ_OP bool_expr' do |ex, v, _eq, n|
277
+ # ex.value = EqOp.new(
278
+ # VarValue.new(v.value.to_s, @names[v.value.to_s]),
279
+ # BoolValue.new(n.value)
280
+ # )
281
+ # end
282
+
283
+ # rule 'expr : VAR EQ_OP STRING' do |ex, v, _eq, n|
284
+ # ex.value = EqOp.new(
285
+ # VarValue.new(v.value.to_s, @names[v.value.to_s]),
286
+ # StringValue.new(n.value)
287
+ # )
288
+ # end
289
+
290
+ # rule 'expr : VAR EQ_OP NUMBER' do |ex, v, _eq, n|
291
+ # ex.value = EqOp.new(
292
+ # VarValue.new(v.value.to_s, @names[v.value.to_s]),
293
+ # NumberValue.new(n.value)
294
+ # )
295
+ # end
296
+ end
297
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Namarara
4
+ VERSION = '0.9.4'
5
+ end
data/lib/namarara.rb ADDED
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'namarara/version'
4
+
5
+ module Namarara; end
6
+
7
+ require 'rly'
8
+
9
+ require 'namarara/lexer'
10
+ require 'namarara/parser'
11
+ require 'namarara/eval_error'
12
+ require 'namarara/errors/var_not_defined'
13
+ require 'namarara/errors/invalid_grammar'
14
+
15
+ module Namarara
16
+ def self.parse_string(line, vars, debug = false)
17
+ parser = Parser.new(Lexer.new)
18
+ parser.names = vars
19
+ parser_bet = parser.parse(line.chomp, debug)
20
+ parser.check_grammar line, parser_bet
21
+
22
+ {
23
+ expr: line,
24
+ tree: parser_bet.to_s,
25
+ errors: parser_bet&.errors&.map { |e| e.message },
26
+ result: parser_bet&.compute
27
+ }
28
+ end
29
+ end
data/namarara.gemspec ADDED
@@ -0,0 +1,44 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'namarara/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'namarara'
8
+ spec.version = Namarara::VERSION
9
+ spec.authors = ['Brendon Torre', 'Glenn Y. Rolland']
10
+ spec.email = ['glenux@glenux.net']
11
+
12
+ spec.summary = %q{A library and tools for parsing boolean expressions}
13
+ spec.description = %q{A library and tools for parsing boolean expressions}
14
+ spec.homepage = 'https://github.com/glenux/namarara/'
15
+ spec.license = 'MIT'
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ if spec.respond_to?(:metadata)
20
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
21
+ else
22
+ raise "RubyGems 2.0 or newer is required to protect against " \
23
+ "public gem pushes."
24
+ end
25
+
26
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
27
+ f.match(%r{^(test|spec|features)/})
28
+ end
29
+ spec.bindir = 'exe'
30
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
+ spec.require_paths = ['lib']
32
+
33
+ spec.add_development_dependency 'thor'
34
+ spec.add_development_dependency 'rly'
35
+ spec.add_development_dependency 'sinatra'
36
+ spec.add_development_dependency "bundler", "~> 1.15"
37
+ spec.add_development_dependency "rake", "~> 10.0"
38
+ spec.add_development_dependency "minitest", "~> 5.0"
39
+ # spec.add_development_dependency "opal"
40
+ spec.add_development_dependency "pry"
41
+ spec.add_development_dependency "rubocop"
42
+ spec.add_development_dependency "rubocop-rspec"
43
+
44
+ end
metadata ADDED
@@ -0,0 +1,197 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: namarara
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.4
5
+ platform: ruby
6
+ authors:
7
+ - Brendon Torre
8
+ - Glenn Y. Rolland
9
+ autorequire:
10
+ bindir: exe
11
+ cert_chain: []
12
+ date: 2020-01-25 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: thor
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rly
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: sinatra
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: bundler
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '1.15'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '1.15'
70
+ - !ruby/object:Gem::Dependency
71
+ name: rake
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '10.0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: '10.0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: minitest
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: '5.0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - "~>"
96
+ - !ruby/object:Gem::Version
97
+ version: '5.0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: pry
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ - !ruby/object:Gem::Dependency
113
+ name: rubocop
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: rubocop-rspec
128
+ requirement: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ type: :development
134
+ prerelease: false
135
+ version_requirements: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ description: A library and tools for parsing boolean expressions
141
+ email:
142
+ - glenux@glenux.net
143
+ executables:
144
+ - namarara-api
145
+ - namarara-cli
146
+ extensions: []
147
+ extra_rdoc_files: []
148
+ files:
149
+ - ".github/workflows/gempush.yml"
150
+ - ".gitignore"
151
+ - ".rubocop.yml"
152
+ - ".ruby-version"
153
+ - ".tool-versions"
154
+ - ".travis.yml"
155
+ - Gemfile
156
+ - LICENSE.txt
157
+ - README.md
158
+ - Rakefile
159
+ - TODO.md
160
+ - bin/console
161
+ - bin/setup
162
+ - demo.rb
163
+ - exe/namarara-api
164
+ - exe/namarara-cli
165
+ - lib/namarara.rb
166
+ - lib/namarara/errors/invalid_grammar.rb
167
+ - lib/namarara/errors/var_not_defined.rb
168
+ - lib/namarara/eval_error.rb
169
+ - lib/namarara/lexer.rb
170
+ - lib/namarara/parser.rb
171
+ - lib/namarara/version.rb
172
+ - namarara.gemspec
173
+ homepage: https://github.com/glenux/namarara/
174
+ licenses:
175
+ - MIT
176
+ metadata:
177
+ allowed_push_host: https://rubygems.org
178
+ post_install_message:
179
+ rdoc_options: []
180
+ require_paths:
181
+ - lib
182
+ required_ruby_version: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - ">="
185
+ - !ruby/object:Gem::Version
186
+ version: '0'
187
+ required_rubygems_version: !ruby/object:Gem::Requirement
188
+ requirements:
189
+ - - ">="
190
+ - !ruby/object:Gem::Version
191
+ version: '0'
192
+ requirements: []
193
+ rubygems_version: 3.0.3
194
+ signing_key:
195
+ specification_version: 4
196
+ summary: A library and tools for parsing boolean expressions
197
+ test_files: []