lamep 0.1 → 0.2

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
2
  SHA1:
3
- metadata.gz: fc0ce5e8f408a519a1c060670e476287be1d9f67
4
- data.tar.gz: c2930b9fbdcdc8c53df84b860f2d331adf53d911
3
+ metadata.gz: a557b4e3fe5b67811e338d680c486345ec1bb7ed
4
+ data.tar.gz: f9ad186e84d8465682dfc46ce32da2362663d1db
5
5
  SHA512:
6
- metadata.gz: fbf0d01e871e567f1e9fb466512a581c17b10631845611b09e02e1374d338a5c6edfd53a7acd480186b8a7df5e14c23dfc025cd26929441eed5863a4087dd466
7
- data.tar.gz: 1e0f8b49ed2b77cadc2cb0aa7b10fbebe9a7d21865647a34e25af1e6a47bcb8769a87cf6c5420e44bf86683cbee3f1f89157e68f582a2fa80e6f5d60e36b60f9
6
+ metadata.gz: 64b5b8d9bed78b78e68b481e86bdc641b4b34dc3b16c8365e2c9d45348c751129a53d9b5cfdfe8271bdabd23f08a5b742f94ef5cabb1e79f3099e710be5ab99f
7
+ data.tar.gz: 67133170d913738facf242cd13a124802306a11ef9d244c47e54049a6820016320691ff258403bfa9e563e909d3173f624d709f8b7ff6fef5213cd547bedf0c5
data/lamep.gemspec CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = 'lamep'
7
- spec.version = 0.1
7
+ spec.version = 0.2
8
8
  spec.authors = ['Martin Svoboda', 'Miroslav Csonka']
9
9
  spec.email = ['miroslav.csonka@gmail.com']
10
10
  spec.summary = %q{Logical and mathematical expression parser}
@@ -5,4 +5,8 @@ class And < Arity2Operators
5
5
  "(#{@left.to_sql} AND #{@right.to_sql})"
6
6
  end
7
7
 
8
+ def evaluate(attributes={})
9
+ !!@left.evaluate(attributes) && !!@right.evaluate(attributes)
10
+ end
11
+
8
12
  end
@@ -5,4 +5,8 @@ class Equal < Arity2Operators
5
5
  "(#{@left.to_sql} = #{@right.to_sql})"
6
6
  end
7
7
 
8
+ def evaluate(values = {})
9
+ @left.evaluate(values) == @right.evaluate(values)
10
+ end
11
+
8
12
  end
@@ -5,4 +5,9 @@ class GreaterThan < Arity2Operators
5
5
  "(#{@left.to_sql} > #{@right.to_sql})"
6
6
  end
7
7
 
8
+
9
+ def evaluate(attributes={})
10
+ @left.evaluate(attributes).to_i > @right.evaluate(attributes).to_i
11
+ end
12
+
8
13
  end
@@ -5,4 +5,8 @@ class GreaterThanEqual < Arity2Operators
5
5
  "(#{@left.to_sql} >= #{@right.to_sql})"
6
6
  end
7
7
 
8
+ def evaluate(attributes={})
9
+ @left.evaluate(attributes).to_i >= @right.evaluate(attributes).to_i
10
+ end
11
+
8
12
  end
@@ -5,4 +5,8 @@ class LessThan < Arity2Operators
5
5
  "(#{@left.to_sql} < #{@right.to_sql})"
6
6
  end
7
7
 
8
+ def evaluate(attributes={})
9
+ @left.evaluate(attributes).to_i < @right.evaluate(attributes).to_i
10
+ end
11
+
8
12
  end
@@ -5,4 +5,8 @@ class LessThanEqual < Arity2Operators
5
5
  "(#{@left.to_sql} <= #{@right.to_sql})"
6
6
  end
7
7
 
8
+ def evaluate(attributes={})
9
+ @left.evaluate(attributes).to_i <= @right.evaluate(attributes).to_i
10
+ end
11
+
8
12
  end
@@ -5,4 +5,8 @@ class NotEqual < Arity2Operators
5
5
  "(#{@left.to_sql} != #{@right.to_sql})"
6
6
  end
7
7
 
8
+ def evaluate(attributes={})
9
+ @left.evaluate(attributes) != @right.evaluate(attributes)
10
+ end
11
+
8
12
  end
@@ -27,4 +27,8 @@ class Operator
27
27
  raise NotImplementedError
28
28
  end
29
29
 
30
+ def evaluate(attributes = {})
31
+ raise NotImplementedError
32
+ end
33
+
30
34
  end
@@ -4,4 +4,8 @@ class Or < Arity2Operators
4
4
  def to_sql
5
5
  "(#{@left.to_sql} OR #{@right.to_sql})"
6
6
  end
7
+
8
+ def evaluate(attributes={})
9
+ !!@left.evaluate(attributes) || !!@right.evaluate(attributes)
10
+ end
7
11
  end
@@ -7,4 +7,8 @@ class UnaryMinus < Arity1Operators
7
7
  -operand.to_i
8
8
  end
9
9
 
10
+ def evaluate(attributes={})
11
+ -@operand.evaluate(attributes).to_i
12
+ end
13
+
10
14
  end
@@ -8,4 +8,12 @@ class ValueExpression < Arity1Operators
8
8
  operand
9
9
  end
10
10
 
11
+ def evaluate(attributes = {})
12
+ if attributes.key? @operand
13
+ attributes[@operand]
14
+ else
15
+ @operand
16
+ end
17
+ end
18
+
11
19
  end
@@ -7,10 +7,10 @@ class AbstractSyntaxTreeBuilder
7
7
  def build_tree
8
8
  until @postfix.length == 1
9
9
  operator_index = first_operator_index
10
- fail 'Not enough operators' if operator_index.nil?
10
+ fail NotEnoughOperatorsException if operator_index.nil?
11
11
  exp = Operator.factory!(@postfix.slice!(operator_index))
12
12
  most_left_child = operator_index - exp::ARITY
13
- fail "Not enough operands for operator #{exp}" if most_left_child < 0
13
+ fail NotEnoughOperandsException, expression: exp if most_left_child < 0
14
14
  children = @postfix.slice!(most_left_child, exp::ARITY)
15
15
  @postfix.insert(most_left_child, exp.new(*children))
16
16
  end
@@ -0,0 +1,2 @@
1
+ class MissingLeftParenthesesError < Exception
2
+ end
@@ -0,0 +1,2 @@
1
+ class MissingRightParenthesesError < Exception
2
+ end
@@ -0,0 +1,10 @@
1
+ class NotEnoughOperandsException < Exception
2
+
3
+ attr_reader :expression
4
+
5
+ def initialize(*argv)
6
+ @expression = argv[0].fetch(:expression)
7
+ super
8
+ end
9
+
10
+ end
@@ -0,0 +1,2 @@
1
+ class NotEnoughOperatorsException < Exception
2
+ end
@@ -16,7 +16,7 @@ class ShuntingYard
16
16
  @stack << token
17
17
  when ')'
18
18
  bracket_sum -= 1
19
- fail('Right parentheses mismatch') if bracket_sum < 0
19
+ fail MissingLeftParenthesesError if bracket_sum < 0
20
20
  burn_stack_to_parentheses
21
21
  else
22
22
  if Operator.exists?(token)
@@ -27,12 +27,12 @@ class ShuntingYard
27
27
  end
28
28
  end
29
29
  end
30
- fail('Left parentheses mismatch') if bracket_sum > 0
30
+ fail MissingRightParenthesesError if bracket_sum > 0
31
31
  @output += @stack.reverse
32
32
  @output
33
33
  end
34
34
 
35
- def burn_stack_to_higher_precedence(token)
35
+ private def burn_stack_to_higher_precedence(token)
36
36
  until @stack.empty? || @stack.last == '(' || Operator.precedence!(token) < Operator.precedence!(@stack.last)
37
37
  @output << @stack.pop
38
38
  end
data/lib/lamep.rb ADDED
@@ -0,0 +1,28 @@
1
+ require './lib/lamep/exceptions/not_enough_operands_exception'
2
+ require './lib/lamep/exceptions/not_enough_operators_exception'
3
+ require './lib/lamep/exceptions/missing_left_parentheses_error'
4
+ require './lib/lamep/exceptions/missing_right_parentheses_error'
5
+ require './lib/lamep/Expressions/operator'
6
+ require './lib/lamep/Expressions/arity1_operators'
7
+ require './lib/lamep/Expressions/arity2_operators'
8
+ require './lib/lamep/Expressions/value_expression'
9
+ require './lib/lamep/token_parser'
10
+ require './lib/lamep/shunting_yard'
11
+ require './lib/lamep/Expressions/equal'
12
+ require './lib/lamep/Expressions/greater_than'
13
+ require './lib/lamep/Expressions/less_than'
14
+ require './lib/lamep/Expressions/greater_than_equal'
15
+ require './lib/lamep/Expressions/less_than_equal'
16
+ require './lib/lamep/Expressions/and'
17
+ require './lib/lamep/Expressions/or'
18
+ require './lib/lamep/Expressions/unary_minus'
19
+ require './lib/lamep/Expressions/not_equal'
20
+ require './lib/lamep/abstract_syntax_tree_builder'
21
+
22
+ class Lamep
23
+ def evaluate(expression, attributes={})
24
+ tokens = TokenParser.new.parse(expression)
25
+ postfix = ShuntingYard.new(tokens).postfix
26
+ AbstractSyntaxTreeBuilder.new(postfix).build_tree.evaluate(attributes)
27
+ end
28
+ end
@@ -57,11 +57,11 @@ describe AbstractSyntaxTreeBuilder do
57
57
  end
58
58
 
59
59
  it 'only operands' do
60
- expect {AbstractSyntaxTreeBuilder.new(%w(materiál cena)).build_tree }.to raise_error(RuntimeError)
60
+ expect {AbstractSyntaxTreeBuilder.new(%w(materiál cena)).build_tree }.to raise_error(NotEnoughOperatorsException)
61
61
  end
62
62
 
63
63
  it 'only operators' do
64
- expect {AbstractSyntaxTreeBuilder.new(%w(&& -)).build_tree }.to raise_error(RuntimeError)
64
+ expect {AbstractSyntaxTreeBuilder.new(%w(&& -)).build_tree }.to raise_error(NotEnoughOperandsException)
65
65
  end
66
66
 
67
67
  end
@@ -0,0 +1,66 @@
1
+ require './spec/spec_helper'
2
+
3
+ describe 'Evaluating of expressions' do
4
+
5
+ def matches?(filter, values={})
6
+ tokens = TokenParser.new.parse(filter)
7
+ postfix = ShuntingYard.new(tokens).postfix
8
+ AbstractSyntaxTreeBuilder.new(postfix).build_tree.evaluate(values)
9
+ end
10
+
11
+ describe Equal do
12
+
13
+ it 'is false' do
14
+ expect(matches?('true = false')).to eq false
15
+ expect(matches?('true = true')).to eq true
16
+ end
17
+
18
+ it 'replacing value holders with actual values' do
19
+ expect(matches?('name = mirek', { 'name' => 'mirek' })).to eq true
20
+ expect(matches?('name = mirek', { 'name' => 'Tomáš' })).to eq false
21
+ end
22
+
23
+ end
24
+
25
+
26
+ it GreaterThan do
27
+ expect(matches?('price > 200', { 'price' => '300' })).to eq true
28
+ expect(matches?('price > 200', { 'price' => 150 })).to eq false
29
+ end
30
+
31
+ it LessThan do
32
+ expect(matches?('(price < 200)', { 'price' => 150 })).to eq true
33
+ expect(matches?('(price < 200)', { 'price' => 500 })).to eq false
34
+ end
35
+
36
+ it GreaterThanEqual do
37
+ expect(matches?('price >= 200', { 'price' => '200' })).to eq true
38
+ expect(matches?('price >= 200', { 'price' => 201 })).to eq true
39
+ expect(matches?('price >= 200', { 'price' => 199 })).to eq false
40
+ end
41
+
42
+ it LessThanEqual do
43
+ expect(matches?('(price <= 200)', { 'price' => 201 })).to eq false
44
+ expect(matches?('(price <= 200)', { 'price' => 200 })).to eq true
45
+ expect(matches?('(price <= 200)', { 'price' => 199 })).to eq true
46
+ end
47
+
48
+ it And do
49
+ expect(matches?('(price > 200) && price < 500', { 'price' => 400 })).to eq true
50
+ end
51
+
52
+ it NotEqual do
53
+ expect(matches?('name != mirek')).to eq true
54
+ expect(matches?('name != name')).to eq false
55
+ end
56
+
57
+ it Or do
58
+ expect(matches?('(price > 200) || (category = 1)', { 'price' => 0, 'category' => '1' })).to eq true
59
+ expect(matches?('price > 200 || category = 1', { 'price' => '0', 'category' => '0' })).to eq false
60
+ end
61
+
62
+ it UnaryMinus do
63
+ expect(matches?('-1 = -(1)', {})).to eq true
64
+ end
65
+
66
+ end
@@ -35,8 +35,8 @@ describe ShuntingYard do
35
35
  it 'brackets' do
36
36
  returns %w(( cena > 180 )), %w(cena 180 >)
37
37
  returns %w(( ( cena ) > ( 180 ) )), %w(cena 180 >)
38
- expect { ShuntingYard.new(%w{( cena ) > 180 )}).postfix }.to raise_error(RuntimeError)
39
- expect { ShuntingYard.new(%w{((( cena ) > 180 )}).postfix }.to raise_error(RuntimeError)
38
+ expect { ShuntingYard.new(%w{( cena ) > 180 )}).postfix }.to raise_error(MissingLeftParenthesesError )
39
+ expect { ShuntingYard.new(%w{( ( ( cena ) > 180 )}).postfix }.to raise_error(MissingRightParenthesesError)
40
40
  end
41
41
 
42
42
  it 'difficult cases' do
data/spec/spec_helper.rb CHANGED
@@ -1,19 +1,4 @@
1
- require './lib/lamep/Expressions/operator'
2
- require './lib/lamep/Expressions/arity1_operators'
3
- require './lib/lamep/Expressions/arity2_operators'
4
- require './lib/lamep/Expressions/value_expression'
5
- require './lib/lamep/token_parser'
6
- require './lib/lamep/shunting_yard'
7
- require './lib/lamep/Expressions/equal'
8
- require './lib/lamep/Expressions/greater_than'
9
- require './lib/lamep/Expressions/less_than'
10
- require './lib/lamep/Expressions/greater_than_equal'
11
- require './lib/lamep/Expressions/less_than_equal'
12
- require './lib/lamep/Expressions/and'
13
- require './lib/lamep/Expressions/or'
14
- require './lib/lamep/Expressions/unary_minus'
15
- require './lib/lamep/Expressions/not_equal'
16
- require './lib/lamep/abstract_syntax_tree_builder'
1
+ require './lib/lamep'
17
2
 
18
3
  RSpec.configure do |config|
19
4
  # rspec-expectations config goes here. You can use an alternate
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lamep
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.1'
4
+ version: '0.2'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Martin Svoboda
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-01-14 00:00:00.000000000 Z
12
+ date: 2015-01-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -67,6 +67,7 @@ files:
67
67
  - README.md
68
68
  - Rakefile
69
69
  - lamep.gemspec
70
+ - lib/lamep.rb
70
71
  - lib/lamep/Expressions/and.rb
71
72
  - lib/lamep/Expressions/arity1_operators.rb
72
73
  - lib/lamep/Expressions/arity2_operators.rb
@@ -81,10 +82,15 @@ files:
81
82
  - lib/lamep/Expressions/unary_minus.rb
82
83
  - lib/lamep/Expressions/value_expression.rb
83
84
  - lib/lamep/abstract_syntax_tree_builder.rb
85
+ - lib/lamep/exceptions/missing_left_parentheses_error.rb
86
+ - lib/lamep/exceptions/missing_right_parentheses_error.rb
87
+ - lib/lamep/exceptions/not_enough_operands_exception.rb
88
+ - lib/lamep/exceptions/not_enough_operators_exception.rb
84
89
  - lib/lamep/shunting_yard.rb
85
90
  - lib/lamep/token_parser.rb
86
91
  - spec/lib/Expressions/operators_spec.rb
87
92
  - spec/lib/abstract_syntax_tree_builder_spec.rb
93
+ - spec/lib/evaluation_spec.rb
88
94
  - spec/lib/shunting_yard_spec.rb
89
95
  - spec/lib/token_parser_spec.rb
90
96
  - spec/spec_helper.rb
@@ -115,6 +121,7 @@ summary: Logical and mathematical expression parser
115
121
  test_files:
116
122
  - spec/lib/Expressions/operators_spec.rb
117
123
  - spec/lib/abstract_syntax_tree_builder_spec.rb
124
+ - spec/lib/evaluation_spec.rb
118
125
  - spec/lib/shunting_yard_spec.rb
119
126
  - spec/lib/token_parser_spec.rb
120
127
  - spec/spec_helper.rb