evaluator 0.1.5
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.
- 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
|