evaluator 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest.txt +5 -0
- data/README.markdown +35 -0
- data/Rakefile +9 -0
- data/lib/evaluator.rb +192 -0
- data/test/test_evaluator.rb +169 -0
- metadata +68 -0
data/Manifest.txt
ADDED
data/README.markdown
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
README
|
2
|
+
======
|
3
|
+
|
4
|
+
Evaluator is a mathematical expression evaluator for infix notation. It supports variables and functions.
|
5
|
+
|
6
|
+
Usage
|
7
|
+
-----
|
8
|
+
|
9
|
+
require 'evaluator'
|
10
|
+
puts Evaluator('1+1')
|
11
|
+
puts Evaluator('sin pi')
|
12
|
+
|
13
|
+
See the test cases for more examples.
|
14
|
+
|
15
|
+
Calculator
|
16
|
+
----------
|
17
|
+
|
18
|
+
A small calculator program (calc.rb) is provided with this library. You can use
|
19
|
+
it as follows:
|
20
|
+
|
21
|
+
$ ./calc.rb
|
22
|
+
> number := 10
|
23
|
+
10
|
24
|
+
> number * 3
|
25
|
+
30
|
26
|
+
> 1 [joule] in [MeV]
|
27
|
+
6241509647120.42 MeV
|
28
|
+
|
29
|
+
The calculator loads a few natural constants at startup (calc.startup). For unit support
|
30
|
+
my minad-units library is used. Units are denoted in brackets e.g. [meter], [kV] etc
|
31
|
+
|
32
|
+
Authors
|
33
|
+
-------
|
34
|
+
|
35
|
+
Daniel Mendler
|
data/Rakefile
ADDED
data/lib/evaluator.rb
ADDED
@@ -0,0 +1,192 @@
|
|
1
|
+
require 'complex'
|
2
|
+
begin
|
3
|
+
require 'units'
|
4
|
+
rescue LoadError
|
5
|
+
end
|
6
|
+
|
7
|
+
module Evaluator
|
8
|
+
def self.infix(priority, unary = nil, &block) [false, priority, lambda(&block), unary] end
|
9
|
+
def self.prefix(&block) [true, 1e5, lambda(&block)] end
|
10
|
+
|
11
|
+
VERSION = '0.1.5'
|
12
|
+
OPERATOR = {
|
13
|
+
'in' => infix(0) do |a,b|
|
14
|
+
raise(RuntimeError, 'Unit support not available') if !a.respond_to? :in
|
15
|
+
a.in(b)
|
16
|
+
end,
|
17
|
+
'||' => infix(1) {|a,b| a || b },
|
18
|
+
'&&' => infix(2) {|a,b| a && b },
|
19
|
+
'==' => infix(3) {|a,b| a == b },
|
20
|
+
'!=' => infix(3) {|a,b| a != b },
|
21
|
+
'<=' => infix(3) {|a,b| a <= b },
|
22
|
+
'>=' => infix(3) {|a,b| a >= b },
|
23
|
+
'<' => infix(3) {|a,b| a < b },
|
24
|
+
'>' => infix(3) {|a,b| a > b },
|
25
|
+
'+' => infix(4, 'plus') {|a,b| a + b },
|
26
|
+
'-' => infix(4, 'minus') {|a,b| a - b },
|
27
|
+
'>>' => infix(5) {|a,b| a >> b },
|
28
|
+
'<<' => infix(5) {|a,b| a << b },
|
29
|
+
'&' => infix(6) {|a,b| a & b },
|
30
|
+
'|' => infix(6) {|a,b| a | b },
|
31
|
+
'^' => infix(6) {|a,b| a ^ b },
|
32
|
+
'*' => infix(7) {|a,b| a * b },
|
33
|
+
'/' => infix(7) {|a,b| a / b },
|
34
|
+
'%' => infix(7) {|a,b| a % b },
|
35
|
+
'div' => infix(7) {|a,b| a.div b },
|
36
|
+
'**' => infix(8) {|a,b| a ** b },
|
37
|
+
'gcd' => prefix {|x,y| x.gcd(y) },
|
38
|
+
'lcm' => prefix {|x,y| x.lcm(y) },
|
39
|
+
'sin' => prefix {|x| Math.sin(x) },
|
40
|
+
'cos' => prefix {|x| Math.cos(x) },
|
41
|
+
'tan' => prefix {|x| Math.tan(x) },
|
42
|
+
'sinh' => prefix {|x| Math.sinh(x) },
|
43
|
+
'cosh' => prefix {|x| Math.cosh(x) },
|
44
|
+
'tanh' => prefix {|x| Math.tanh(x) },
|
45
|
+
'asin' => prefix {|x| Math.asin(x) },
|
46
|
+
'acos' => prefix {|x| Math.acos(x) },
|
47
|
+
'atan' => prefix {|x| Math.atan(x) },
|
48
|
+
'asinh' => prefix {|x| Math.asinh(x) },
|
49
|
+
'acosh' => prefix {|x| Math.acosh(x) },
|
50
|
+
'atanh' => prefix {|x| Math.atanh(x) },
|
51
|
+
'sqrt' => prefix {|x| Math.sqrt(x) },
|
52
|
+
'log' => prefix {|x| Math.log(x) },
|
53
|
+
'log10' => prefix {|x| Math.log10(x) },
|
54
|
+
'log2' => prefix {|x| Math.log(x)/Math.log(2) },
|
55
|
+
'exp' => prefix {|x| Math.exp(x) },
|
56
|
+
'erf' => prefix {|x| Math.erf(x) },
|
57
|
+
'erfc' => prefix {|x| Math.erfc(x) },
|
58
|
+
'floor' => prefix {|x| x.floor },
|
59
|
+
'ceil' => prefix {|x| x.ceil },
|
60
|
+
'string' => prefix {|x| x.to_s },
|
61
|
+
'int' => prefix {|x| x.to_i },
|
62
|
+
'float' => prefix {|x| x.to_f },
|
63
|
+
'rand' => prefix {|| rand },
|
64
|
+
'conj' => prefix {|x| x.conj },
|
65
|
+
'im' => prefix {|x| x.imag },
|
66
|
+
're' => prefix {|x| x.real },
|
67
|
+
'round' => prefix {|x| x.round },
|
68
|
+
'abs' => prefix {|x| x.abs },
|
69
|
+
'minus' => prefix {|x| -x },
|
70
|
+
'plus' => prefix {|x| x },
|
71
|
+
'!' => prefix {|x| !x },
|
72
|
+
'~' => prefix {|x| ~x },
|
73
|
+
'substr' => prefix {|x,a,b| x.slice(a,b) },
|
74
|
+
'len' => prefix {|x| x.length },
|
75
|
+
'tolower' => prefix {|x| x.downcase },
|
76
|
+
'toupper' => prefix {|x| x.upcase },
|
77
|
+
'strip' => prefix {|x| x.strip },
|
78
|
+
'reverse' => prefix {|x| x.reverse },
|
79
|
+
'index' => prefix {|x,y| x.index(y) },
|
80
|
+
'rindex' => prefix {|x,y| x.rindex(y) },
|
81
|
+
'=' => '==',
|
82
|
+
'or' => '||',
|
83
|
+
'and' => '&&',
|
84
|
+
'mod' => '%',
|
85
|
+
'ln' => 'log',
|
86
|
+
'imag' => 'im',
|
87
|
+
'real' => 're',
|
88
|
+
'count' => 'len',
|
89
|
+
'size' => 'len',
|
90
|
+
'length' => 'len',
|
91
|
+
'trim' => 'strip',
|
92
|
+
'downcase' => 'tolower',
|
93
|
+
'upcase' => 'toupper',
|
94
|
+
'slice' => 'substr',
|
95
|
+
'arcsin' => 'asin',
|
96
|
+
'arccos' => 'acos',
|
97
|
+
'arctan' => 'atan',
|
98
|
+
'arcsinh' => 'asinh',
|
99
|
+
'arccosh' => 'asinh',
|
100
|
+
'arctanh' => 'atanh',
|
101
|
+
}
|
102
|
+
CONSTANTS = {
|
103
|
+
'true' => true,
|
104
|
+
'false' => false,
|
105
|
+
'nil' => nil,
|
106
|
+
'e' => Math::E,
|
107
|
+
'pi' => Math::PI,
|
108
|
+
'i' => Complex::I,
|
109
|
+
}
|
110
|
+
STRING = /^(?:'(?:\\'|[^'])*'|"(?:\\"|[^"])*")$/
|
111
|
+
REAL = /^(?:(?:\d*\.\d+|\d+\.\d*)(?:[eE][-+]?\d+)?|\d+[eE][-+]?\d+)$/
|
112
|
+
HEX = /^0[xX][\dA-Fa-f]+$/
|
113
|
+
OCT = /^0[0-7]+$/
|
114
|
+
DEC = /^\d+$/
|
115
|
+
SYMBOL = /^[a-zA-Z_][\w_]*$/
|
116
|
+
UNIT = /^\[[^\]]+\]$/
|
117
|
+
VALUE_TOKENS = [UNIT, STRING, REAL, HEX, OCT, DEC, SYMBOL].map {|x| x.source[1..-2] }
|
118
|
+
OPERATOR_TOKENS = OPERATOR.keys.flatten.sort { |a,b| b.length <=> a.length}.map { |x| Regexp.quote(x) }
|
119
|
+
TOKENIZER = Regexp.new((VALUE_TOKENS + OPERATOR_TOKENS + ['\\(', '\\)', ',']).join('|'))
|
120
|
+
|
121
|
+
def self.eval(expr, vars = {})
|
122
|
+
vars = Hash[*vars.merge(CONSTANTS).map {|k,v| [k.to_s.downcase, v] }.flatten]
|
123
|
+
stack, result, unary = [], [], true
|
124
|
+
expr.to_s.scan(TOKENIZER).each do |tok|
|
125
|
+
if tok == '('
|
126
|
+
stack << '('
|
127
|
+
unary = true
|
128
|
+
elsif tok == ')'
|
129
|
+
exec(result, stack.pop) while !stack.empty? && stack.last != '('
|
130
|
+
raise(SyntaxError, 'Unexpected token )') if stack.empty?
|
131
|
+
stack.pop
|
132
|
+
unary = false
|
133
|
+
elsif tok == ','
|
134
|
+
exec(result, stack.pop) while !stack.empty? && stack.last != '('
|
135
|
+
unary = true
|
136
|
+
elsif operator = OPERATOR[tok.downcase]
|
137
|
+
# Check for alias
|
138
|
+
tok = String === operator ? operator : tok.downcase
|
139
|
+
operator = OPERATOR[tok]
|
140
|
+
if operator[0]
|
141
|
+
stack << '*' if !unary
|
142
|
+
# Prefix operator
|
143
|
+
stack << tok
|
144
|
+
elsif unary && operator[3]
|
145
|
+
# Alternative prefix operator
|
146
|
+
stack << operator[3]
|
147
|
+
else
|
148
|
+
# Infix operator
|
149
|
+
exec(result, stack.pop) while !stack.empty? && stack.last != '(' && OPERATOR[stack.last][1] >= operator[1]
|
150
|
+
stack << tok
|
151
|
+
end
|
152
|
+
unary = true
|
153
|
+
else
|
154
|
+
val = case tok
|
155
|
+
when UNIT
|
156
|
+
if tok.respond_to? :to_unit
|
157
|
+
tok[1..-2].to_unit
|
158
|
+
else
|
159
|
+
raise(RuntimeError, 'Unit support not available')
|
160
|
+
end
|
161
|
+
when STRING then tok[1..-2].gsub(/\\"/, '"').gsub(/\\'/, "'")
|
162
|
+
when REAL then tok.to_f
|
163
|
+
when HEX then tok.to_i(16)
|
164
|
+
when OCT then tok.to_i(8)
|
165
|
+
when DEC then tok.to_i(10)
|
166
|
+
when SYMBOL
|
167
|
+
tok.downcase!
|
168
|
+
raise(NameError, "Symbol #{tok} is undefined") if !vars.include?(tok)
|
169
|
+
vars[tok]
|
170
|
+
end
|
171
|
+
stack << '*' if !unary
|
172
|
+
result << val
|
173
|
+
unary = false
|
174
|
+
end
|
175
|
+
end
|
176
|
+
exec(result, stack.pop) while !stack.empty?
|
177
|
+
result.last
|
178
|
+
end
|
179
|
+
|
180
|
+
def self.exec(result, op)
|
181
|
+
raise(SyntaxError, "Unexpected token #{op}") if !OPERATOR.include?(op)
|
182
|
+
fn = OPERATOR[op][2]
|
183
|
+
raise(SyntaxError, "Not enough operands for #{op}") if result.size < fn.arity
|
184
|
+
result << fn[*result.slice!(-fn.arity, fn.arity)]
|
185
|
+
end
|
186
|
+
|
187
|
+
private_class_method :infix, :prefix, :exec
|
188
|
+
end
|
189
|
+
|
190
|
+
def Evaluator(expr, vars = {})
|
191
|
+
Evaluator.eval(expr, vars)
|
192
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'evaluator'
|
3
|
+
|
4
|
+
class TestEvaluator < Test::Unit::TestCase
|
5
|
+
def test_binary_operators
|
6
|
+
assert_equal 42, Evaluator('42 || false')
|
7
|
+
assert_equal true, Evaluator('false || nil || true')
|
8
|
+
assert_equal 42, Evaluator('42 or false')
|
9
|
+
assert_equal true, Evaluator('false or nil or true')
|
10
|
+
|
11
|
+
assert_equal 42, Evaluator('true && 42')
|
12
|
+
assert_equal nil, Evaluator('nil && 1')
|
13
|
+
assert_equal 42, Evaluator('true and 42')
|
14
|
+
assert_equal nil, Evaluator('nil and 1')
|
15
|
+
|
16
|
+
assert Evaluator('1+1==2')
|
17
|
+
assert Evaluator("'abc' == 'a'+'b'+'c'")
|
18
|
+
|
19
|
+
assert Evaluator('1+1 != 3')
|
20
|
+
assert Evaluator("'xxx' != 'a'+'b'+'c'")
|
21
|
+
|
22
|
+
assert Evaluator('1<=1')
|
23
|
+
assert Evaluator('1<=2')
|
24
|
+
assert Evaluator('1>=1')
|
25
|
+
assert Evaluator('2>=1')
|
26
|
+
assert(!Evaluator('1<1'))
|
27
|
+
assert Evaluator('1<2')
|
28
|
+
assert(!Evaluator('1>1'))
|
29
|
+
assert Evaluator('2>1')
|
30
|
+
|
31
|
+
assert_equal 3, Evaluator('1+2')
|
32
|
+
assert_equal 'xyz', Evaluator('"x"+"yz"')
|
33
|
+
assert_equal 'a1b', Evaluator("'a'+string 1+'b'")
|
34
|
+
assert_equal 'a1b', Evaluator("'a'+string(1)+'b'")
|
35
|
+
|
36
|
+
assert_equal 3, Evaluator('5-2')
|
37
|
+
assert_equal(-1, Evaluator('3-4'))
|
38
|
+
|
39
|
+
assert_equal 12, Evaluator('3*4')
|
40
|
+
assert_equal 'ababab', Evaluator('"ab"*3')
|
41
|
+
|
42
|
+
assert_equal 3, Evaluator('12/4')
|
43
|
+
|
44
|
+
assert_equal 10, Evaluator('103. div 10.')
|
45
|
+
|
46
|
+
assert_equal 3, Evaluator('7 mod 4')
|
47
|
+
assert_equal 3, Evaluator('7 % 4')
|
48
|
+
|
49
|
+
assert_equal 1024, Evaluator('2 ** 10')
|
50
|
+
|
51
|
+
assert_equal 8, Evaluator('2 << 2')
|
52
|
+
assert_equal 32, Evaluator('256 >> 3')
|
53
|
+
|
54
|
+
assert_equal 2, Evaluator('6 & 2')
|
55
|
+
assert_equal 7, Evaluator('1 | 2 | 4')
|
56
|
+
assert_equal 1, Evaluator('9 ^ 8')
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_unary_operators
|
60
|
+
assert_equal(-1, Evaluator('-1'))
|
61
|
+
assert_equal(-2, Evaluator('-(1+1)'))
|
62
|
+
assert_equal(-42, Evaluator('---42'))
|
63
|
+
assert_equal 42, Evaluator('----42')
|
64
|
+
assert_equal(-9, Evaluator('3*-3'))
|
65
|
+
assert_equal(9, Evaluator('3*+3'))
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_precendence
|
69
|
+
assert_equal 16, Evaluator('1+3*5')
|
70
|
+
assert_equal 16, Evaluator('3*5+1')
|
71
|
+
assert_equal 23, Evaluator('3*5+2**3')
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_constants
|
75
|
+
assert_equal Math::PI, Evaluator('PI')
|
76
|
+
assert_equal Math::E, Evaluator('E')
|
77
|
+
assert_equal Complex::I, Evaluator('I')
|
78
|
+
assert_equal true, Evaluator('trUe')
|
79
|
+
assert_equal false, Evaluator('fAlSe')
|
80
|
+
assert_equal nil, Evaluator('niL')
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_numeric_functions
|
84
|
+
assert_equal 13, Evaluator('gcd(26, 39)')
|
85
|
+
assert_equal 78, Evaluator('lcm(26, 39)')
|
86
|
+
assert_equal Math.cos(42), Evaluator('cos 42')
|
87
|
+
assert_equal Math.sin(42), Evaluator('sin 42')
|
88
|
+
assert_equal Math.cos(42), Evaluator('cos 42')
|
89
|
+
assert_equal Math.tan(42), Evaluator('tan 42')
|
90
|
+
assert_equal Math.sinh(42), Evaluator('sinh 42')
|
91
|
+
assert_equal Math.cosh(42), Evaluator('cosh 42')
|
92
|
+
assert_equal Math.tanh(42), Evaluator('tanh 42')
|
93
|
+
assert_equal Math.asin(0.5), Evaluator('asin .5')
|
94
|
+
assert_equal Math.acos(0.5), Evaluator('acos .5')
|
95
|
+
assert_equal Math.atan(0.5), Evaluator('atan .5')
|
96
|
+
assert_equal Math.asinh(0.5), Evaluator('asinh .5')
|
97
|
+
assert_equal Math.atanh(0.5), Evaluator('atanh .5')
|
98
|
+
assert_equal Math.sqrt(42) + 1, Evaluator('sqrt 42 + 1')
|
99
|
+
assert_equal Math.log(42) + 3, Evaluator('log 42 + 3')
|
100
|
+
assert_equal Math.log(42) + 3, Evaluator('ln 42 + 3')
|
101
|
+
assert_equal Math.log10(42) + 3, Evaluator('log10 42 + 3')
|
102
|
+
assert_equal Math.log(42)/Math.log(2) + 3, Evaluator('log2 42 + 3')
|
103
|
+
assert_equal 3 * Math.exp(42), Evaluator('3 * exp 42')
|
104
|
+
assert_equal Math.erf(2), Evaluator('erf 2')
|
105
|
+
assert_equal Math.erfc(2), Evaluator('erfc 2')
|
106
|
+
assert_equal 42, Evaluator('floor 42.3')
|
107
|
+
assert_equal 42, Evaluator('ceil 41.6')
|
108
|
+
assert_equal 3.5, Evaluator('float("3.5")')
|
109
|
+
assert_equal "3.5", Evaluator('string(3.5)')
|
110
|
+
assert_equal 3, Evaluator('int("3.5")')
|
111
|
+
assert_equal 3, Evaluator('int(3.6)')
|
112
|
+
srand(42); x = rand; srand(42)
|
113
|
+
assert_equal x, Evaluator('rand')
|
114
|
+
assert_equal Complex(1,-2), Evaluator('conj(1+2*i)')
|
115
|
+
assert_equal 2, Evaluator('Im(1+2*i)')
|
116
|
+
assert_equal 1, Evaluator('Re(1+2*i)')
|
117
|
+
assert_equal 3, Evaluator('round(3.4)')
|
118
|
+
assert_equal 4, Evaluator('round(3.5)')
|
119
|
+
assert_equal 6, Evaluator('abs -6')
|
120
|
+
assert_equal 3, Evaluator('plus 3')
|
121
|
+
assert_equal(-3, Evaluator('minus 3'))
|
122
|
+
assert_equal false, Evaluator('!3')
|
123
|
+
assert_equal ~3, Evaluator('~3')
|
124
|
+
end
|
125
|
+
|
126
|
+
def test_string_functions
|
127
|
+
assert_equal 'bcd', Evaluator('substr("abcde", 1, 3)')
|
128
|
+
assert_equal 4, Evaluator('len("abcd")')
|
129
|
+
assert_equal 'abc', Evaluator('strip " abc "')
|
130
|
+
assert_equal 'cba', Evaluator('reverse "abc"')
|
131
|
+
assert_equal 2, Evaluator('index("abcdefg", "cde")')
|
132
|
+
assert_equal 7, Evaluator('rindex("abcdefgcdef", "cde")')
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_variables
|
136
|
+
assert_equal 14, Evaluator('a+b*c', :a => 2, :b => 3, :c => 4)
|
137
|
+
assert_equal 14, Evaluator('a+b*C', 'A' => 2, 'b' => 3, :c => 4)
|
138
|
+
assert_equal 14, Evaluator('alpha+beta*GAMMA', 'ALPHA' => 2, 'bEtA' => 3, 'gamma' => 4)
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_errors
|
142
|
+
assert_raise(SyntaxError) { Evaluator('(((((((((((((3+3))') }
|
143
|
+
assert_raise(SyntaxError) { Evaluator('1+2)') }
|
144
|
+
assert_raise(SyntaxError) { Evaluator('1+2+3+') }
|
145
|
+
assert_raise(SyntaxError) { Evaluator('1 + floor') }
|
146
|
+
assert_raise(NameError) { Evaluator('42*a+3') }
|
147
|
+
assert_raise(NameError) { Evaluator('abc10') }
|
148
|
+
assert_raise(NameError) { Evaluator('abc10d') }
|
149
|
+
end
|
150
|
+
|
151
|
+
def test_numbers
|
152
|
+
assert_equal 0xABCDEF123, Evaluator('0xABCDEF123')
|
153
|
+
assert_equal 01234, Evaluator('01234')
|
154
|
+
assert_equal 234, Evaluator('234 ')
|
155
|
+
assert_equal 0.123, Evaluator('.123')
|
156
|
+
assert_equal 0.123, Evaluator('0.123')
|
157
|
+
assert_equal 123.0, Evaluator('123.')
|
158
|
+
assert_equal 123e-42, Evaluator('123e-42')
|
159
|
+
assert_equal 0.123e-42, Evaluator('.123e-42')
|
160
|
+
assert_equal 2.123e-42, Evaluator('2.123e-42')
|
161
|
+
end
|
162
|
+
|
163
|
+
def test_strings
|
164
|
+
assert_equal "abc'a", Evaluator('"abc\'a"')
|
165
|
+
assert_equal 'abc"a', Evaluator('"abc\"a"')
|
166
|
+
assert_equal 'abc"a', Evaluator("'abc\"a'")
|
167
|
+
assert_equal "abc'a", Evaluator("'abc\\'a'")
|
168
|
+
end
|
169
|
+
end
|
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: evaluator
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.5
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Daniel Mendler
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-04-13 00:00:00 +02:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: hoe
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.8.3
|
24
|
+
version:
|
25
|
+
description:
|
26
|
+
email:
|
27
|
+
- mail@daniel-mendler.de
|
28
|
+
executables: []
|
29
|
+
|
30
|
+
extensions: []
|
31
|
+
|
32
|
+
extra_rdoc_files:
|
33
|
+
- Manifest.txt
|
34
|
+
files:
|
35
|
+
- lib/evaluator.rb
|
36
|
+
- test/test_evaluator.rb
|
37
|
+
- README.markdown
|
38
|
+
- Rakefile
|
39
|
+
- Manifest.txt
|
40
|
+
has_rdoc: true
|
41
|
+
homepage:
|
42
|
+
post_install_message:
|
43
|
+
rdoc_options:
|
44
|
+
- --main
|
45
|
+
- README.markdown
|
46
|
+
require_paths:
|
47
|
+
- lib
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: "0"
|
53
|
+
version:
|
54
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: "0"
|
59
|
+
version:
|
60
|
+
requirements: []
|
61
|
+
|
62
|
+
rubyforge_project: evaluator
|
63
|
+
rubygems_version: 1.3.1
|
64
|
+
signing_key:
|
65
|
+
specification_version: 2
|
66
|
+
summary: Mathematical expression evaluator
|
67
|
+
test_files:
|
68
|
+
- test/test_evaluator.rb
|