namarara 0.9.4

Sign up to get free protection for your applications and to get access to all the features.
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: []