math_engine 0.2.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -6,7 +6,7 @@ Install with
6
6
 
7
7
  gem install math_engine
8
8
 
9
- The only dependency is on my other gem, lexr[http://github.com/michaelbaldry/lexr], which is really lightweight and has no external dependencies.
9
+ The only dependency is [lexr](http://github.com/michaelbaldry/lexr), which is really lightweight and has no external dependencies.
10
10
 
11
11
  ## An example: Expressions
12
12
 
@@ -22,14 +22,40 @@ results in an output of
22
22
 
23
23
  65.0
24
24
  70.0
25
+
26
+ extending is easy using functions, you can add single functions using MathEngine.define
27
+
28
+ engine.context.define :add_em do |x, y|
29
+ x + y
30
+ end
31
+
32
+ or you can write all your functions in a class and add the class
33
+
34
+ class SomeFunctions
35
+ def add_em(x, y)
36
+ x + y
37
+ end
38
+ end
39
+
40
+ engine.context.include_library SomeFunctions.new
25
41
 
42
+ and calling them with
43
+
44
+ engine.evaluate("1 + 1 + add_em(2, 2)")
45
+
46
+ All functions are pulled in from the built in Math class by default, so all the standard ruby math functions are available (cos, sin, tan etc)
47
+
26
48
  if you missed a closing parenthesis, had an operator where it wasn't meant to be, you might get something like this:
27
49
 
28
50
  Unexpected multiplication(*), expected: number, variable name or open_parenthesis
29
51
 
30
52
  and that is pretty much every feature so far. Please let me know of any bugs or additions that you'd like to see!
31
53
 
54
+ ## Contributors
55
+
56
+ Mario de la Ossa (mdelaossa): Handling of complex numbers and upgraded to work with 1.9.X
57
+
32
58
  ## License
33
59
 
34
60
  See the LICENSE file included with the distribution for licensing and
35
- copyright details.
61
+ copyright details.
data/lib/context.rb ADDED
@@ -0,0 +1,63 @@
1
+ class MathEngine
2
+ class Context
3
+ DEFAULT_OPTIONS = {case_sensitive: true}
4
+
5
+ def initialize(opts = {})
6
+ @opts = DEFAULT_OPTIONS.merge(opts)
7
+ @variables = {}
8
+ @dynamic_library = Class.new.new
9
+ @libraries = [@dynamic_library, Math]
10
+ end
11
+
12
+ def get(variable_name)
13
+ @variables[key variable_name]
14
+ end
15
+
16
+ def set(variable_name, value)
17
+ raise MathEngine::UnableToModifyConstantError.new(key variable_name) if constant?(key variable_name) &&
18
+ get(variable_name)
19
+
20
+ @variables[key variable_name] = value
21
+ end
22
+
23
+ def define(function_name, func = nil, &block)
24
+ @dynamic_library.class.send :define_method, function_name.to_sym do |*args|
25
+ func ? func.call(*args) : block.call(*args)
26
+ end
27
+ end
28
+
29
+ def call(function_name, *args)
30
+ library = library_for_function(function_name)
31
+ raise UnknownFunctionError.new(function_name) unless library
32
+ library.send(function_name, *args)
33
+ end
34
+
35
+ def include_library(library)
36
+ @libraries << library
37
+ end
38
+
39
+ def constants
40
+ @variables.keys.select { |variable_name| constant?(variable_name) }
41
+ end
42
+
43
+ def variables
44
+ @variables.keys - constants
45
+ end
46
+
47
+ private
48
+
49
+ def constant?(variable_name)
50
+ variable_name.upcase == variable_name
51
+ end
52
+
53
+ def key(variable_name)
54
+ return variable_name if @opts[:case_sensitive]
55
+ result = @variables.keys.select { |key| key.downcase == variable_name.downcase }.first
56
+ result || variable_name
57
+ end
58
+
59
+ def library_for_function(function_name)
60
+ @libraries.detect { |l| l.methods.include? function_name.to_sym }
61
+ end
62
+ end
63
+ end
data/lib/errors.rb CHANGED
@@ -29,7 +29,7 @@ class MathEngine
29
29
  end
30
30
  end
31
31
 
32
- class UnableToModifyConstant < StandardError
32
+ class UnableToModifyConstantError < StandardError
33
33
  def initialize(constant_name)
34
34
  @constant_name = constant_name
35
35
  end
@@ -38,4 +38,19 @@ class MathEngine
38
38
  "Unable to modify value of constant '#{@constant_name}'"
39
39
  end
40
40
  end
41
+
42
+ class UnknownEvaluatorError < StandardError
43
+ def initialize(evaluator_name, expected_const)
44
+ @evaluator_name = evaluator_name
45
+ @expected_const = expected_const
46
+ end
47
+
48
+ def to_s
49
+ "Unable to find an evaluator called #{@evaluator_name}(#{@expected_const})"
50
+ end
51
+
52
+ def ==(other)
53
+ self.to_s == other.to_s
54
+ end
55
+ end
41
56
  end
@@ -0,0 +1,60 @@
1
+ class MathEngine
2
+ module Evaluators
3
+ class Calculate
4
+ def initialize(context)
5
+ @context = context
6
+ end
7
+
8
+ def literal_number(node)
9
+ node.value
10
+ end
11
+
12
+ def expression(node)
13
+ node.left.evaluate(self)
14
+ end
15
+
16
+ def identifier(node)
17
+ @context.get node.value
18
+ end
19
+
20
+ def assignment(node)
21
+ result = node.right.evaluate(self)
22
+ @context.set(node.left.value, result)
23
+ result
24
+ end
25
+
26
+ def addition(node)
27
+ node.left.evaluate(self) + node.right.evaluate(self)
28
+ end
29
+
30
+ def subtraction(node)
31
+ node.left.evaluate(self) - node.right.evaluate(self)
32
+ end
33
+
34
+ def multiplication(node)
35
+ node.left.evaluate(self) * node.right.evaluate(self)
36
+ end
37
+
38
+ def division(node)
39
+ node.left.evaluate(self) / node.right.evaluate(self)
40
+ end
41
+
42
+ def exponent(node)
43
+ node.left.evaluate(self) ** node.right.evaluate(self)
44
+ end
45
+
46
+ def modulus(node)
47
+ node.left.evaluate(self) % node.right.evaluate(self)
48
+ end
49
+
50
+ def function_call(node)
51
+ parameters = node.right ? node.right.to_a.collect { |p| p.evaluate(self) } : []
52
+ @context.call(node.left, *parameters)
53
+ end
54
+
55
+ def parameters(node)
56
+ node.left.evaluate(self)
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,9 @@
1
+ class MathEngine
2
+ module Evaluators
3
+ def self.find_by_name(name)
4
+ class_name = name.to_s.sub(%r{^[a-z\d]}) { $&.upcase }
5
+ class_name.gsub!(%r{(?:_|(\/))([a-z\d]*)}) { "#{$1}#{$2.capitalize}" }
6
+ MathEngine::Evaluators.const_get(class_name) rescue raise MathEngine::UnknownEvaluatorError.new(name, "MathEngine::Evaluators::#{class_name}")
7
+ end
8
+ end
9
+ end
data/lib/lexer.rb CHANGED
@@ -1,20 +1,26 @@
1
- require 'rubygems'
2
- require 'lexr'
3
-
4
1
  class MathEngine
5
2
  Lexer = Lexr.that {
6
- ignores /\s/ => :whitespace
7
- matches /[a-z][a-z0-9_]*/ => :identifier, :convert_with => lambda { |v| v.to_sym }
8
- matches /[-+]?[0-9]*\.?[0-9]+/ => :number, :convert_with => lambda { |v| Float(v) }
9
- matches ',' => :comma
10
- matches '=' => :assignment
11
- matches '+' => :addition
12
- matches '-' => :subtraction
13
- matches '*' => :multiplication
14
- matches '/' => :division
15
- matches '^' => :exponent
16
- matches '%' => :modulus
17
- matches '(' => :open_parenthesis
18
- matches ')' => :close_parenthesis
3
+ ignores /\s/ => :whitespace
4
+
5
+ legal_place_for_binary_operator = lambda { |prev| [:addition,
6
+ :subtraction,
7
+ :multiplication,
8
+ :division,
9
+ :open_parenthesis,
10
+ :start].include? prev.type }
11
+
12
+ matches ',' => :comma
13
+ matches '=' => :assignment
14
+ matches '+' => :addition, :unless => legal_place_for_binary_operator
15
+ matches '-' => :subtraction, :unless => legal_place_for_binary_operator
16
+ matches '*' => :multiplication, :unless => legal_place_for_binary_operator
17
+ matches '/' => :division, :unless => legal_place_for_binary_operator
18
+ matches '^' => :exponent, :unless => legal_place_for_binary_operator
19
+ matches '%' => :modulus, :unless => legal_place_for_binary_operator
20
+ matches '(' => :open_parenthesis
21
+ matches ')' => :close_parenthesis
22
+
23
+ matches /([-+]?(\d+\.?\d*|\d*\.?\d+)([Ee][-+]?[0-2]?\d{1,2})?[r]?|[-+]?((\d+\.?\d*|\d*\.?\d+)([Ee][-+]?[0-2]?\d{1,2})?)?[i]|[-+]?(\d+\.?\d*|\d*\.?\d+)([Ee][-+]?[0-2]?\d{1,2})?[r]?[-+]((\d+\.?\d*|\d*\.?\d+)([Ee][-+]?[0-2]?\d{1,2})?)?[i])/ => :number, :convert_with => lambda { |v| BigDecimal(v) }
24
+ matches /[a-z][a-z0-9_]*/i => :identifier, :convert_with => lambda { |v| v.to_sym }
19
25
  }
20
- end
26
+ end
data/lib/math_engine.rb CHANGED
@@ -1,55 +1,29 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), 'errors'))
2
- require File.expand_path(File.join(File.dirname(__FILE__), 'lexer'))
3
- require File.expand_path(File.join(File.dirname(__FILE__), 'parser'))
1
+ #require "mathn"
2
+ require "bigdecimal"
3
+
4
+ require_relative "errors"
5
+ require_relative "lexer"
6
+ require_relative "parser"
7
+ require_relative "context"
8
+
9
+ require_relative "evaluators/finders"
10
+ require_relative "evaluators/calculate"
4
11
 
5
12
  class MathEngine
6
- def initialize()
7
- @variables = {}
8
- @dyn_library = Class.new.new
9
- @libraries = [@dyn_library, Math]
10
- end
11
-
12
- def evaluate(expression)
13
- Parser.new(Lexer.new(expression)).parse.evaluate(self)
14
- end
15
-
16
- def set(variable_name, value)
17
- raise UnableToModifyConstant.new(variable_name) if @variables.keys.include? variable_name and variable_name.to_s == variable_name.to_s.upcase
18
- @variables[variable_name] = value
19
- end
20
-
21
- def get(variable_name)
22
- raise UnknownVariableError.new(variable_name) unless @variables.keys.include? variable_name
23
- @variables[variable_name]
24
- end
25
-
26
- def variables
27
- @variables.keys.collect { |k| k.to_s }.reject { |v| v.downcase != v }.sort.collect { |k| k.to_sym }
28
- end
29
-
30
- def constants
31
- @variables.keys.collect { |k| k.to_s }.reject { |v| v.upcase != v }.sort.collect { |k| k.to_sym }
32
- end
13
+ DEFAULT_OPTIONS = {evaluator: :calculate,
14
+ case_sensitive: true}
33
15
 
34
- def call(name, *parameters)
35
- cls = class_for_function(name)
36
- raise UnknownFunctionError.new(name) unless cls
37
- cls.send name, *parameters
16
+ def initialize(opts = {})
17
+ @opts = DEFAULT_OPTIONS.merge(opts)
18
+ @opts[:context] = Context.new(@opts) unless @opts[:context]
38
19
  end
39
20
 
40
- def define(name, func = nil, &block)
41
- @dyn_library.class.send :define_method, name.to_sym do |*args|
42
- func ? func.call(*args) : block.call(*args)
43
- end
44
- end
45
-
46
- def include_library(library)
47
- @libraries << library
21
+ def evaluate(expression)
22
+ evaluator = MathEngine::Evaluators.find_by_name(@opts[:evaluator]).new(context)
23
+ Parser.new(Lexer.new(expression)).parse.evaluate(evaluator)
48
24
  end
49
25
 
50
- private
51
-
52
- def class_for_function(name)
53
- @libraries.detect { |l| l.methods.include? name.to_s }
26
+ def context
27
+ @opts[:context]
54
28
  end
55
- end
29
+ end
data/lib/nodes.rb CHANGED
@@ -1,83 +1,40 @@
1
1
  class MathEngine
2
2
  class Node
3
- attr_reader :left, :right
4
- alias :value :left
3
+ attr_reader :left, :right
4
+ alias :value :left
5
5
 
6
- def initialize(left, right = nil)
7
- @left, @right = left, right
8
- end
9
- end
10
-
11
- class LiteralNumberNode < Node
12
- def evaluate(engine)
13
- value
14
- end
15
- end
16
-
17
- class ExpressionNode < Node
18
- def evaluate(engine)
19
- left.evaluate(engine)
20
- end
21
- end
22
-
23
- class IdentifierNode < Node
24
- def evaluate(engine)
25
- engine.get value
6
+ def initialize(left, right = nil)
7
+ @left, @right = left, right
8
+ end
9
+
10
+ def evaluate(evaluator)
11
+ evaluator.send(method_name, self)
12
+ end
13
+
14
+ private
15
+
16
+ def method_name
17
+ class_name = self.class.name[0..-5]
18
+ class_name = class_name[class_name.rindex("::")+2..-1] if class_name.rindex("::")
19
+ method_name = class_name.gsub(%r{([A-Z\d]+)([A-Z][a-z])},'\1_\2').gsub(%r{([a-z\d])([A-Z])},'\1_\2').downcase
26
20
  end
27
21
  end
28
22
 
29
- class AssignmentNode < Node
30
- def evaluate(engine)
31
- result = right.evaluate(engine)
32
- engine.set(left.value, result)
33
- result
34
- end
35
- end
23
+ class LiteralNumberNode < Node ; end
24
+ class ExpressionNode < Node ; end
25
+ class IdentifierNode < Node ; end
26
+ class AssignmentNode < Node ; end
36
27
 
37
- class AdditionNode < Node
38
- def evaluate(engine)
39
- left.evaluate(engine) + right.evaluate(engine)
40
- end
41
- end
28
+ class AdditionNode < Node ; end
29
+ class SubtractionNode < Node ; end
30
+ class MultiplicationNode < Node ; end
31
+ class DivisionNode < Node ; end
32
+ class ExponentNode < Node ; end
33
+ class ModulusNode < Node ; end
42
34
 
43
- class SubtractionNode < Node
44
- def evaluate(engine)
45
- left.evaluate(engine) - right.evaluate(engine)
46
- end
47
- end
48
- class MultiplicationNode < Node
49
- def evaluate(engine)
50
- left.evaluate(engine) * right.evaluate(engine)
51
- end
52
- end
53
- class DivisionNode < Node
54
- def evaluate(engine)
55
- left.evaluate(engine) / right.evaluate(engine)
56
- end
57
- end
58
- class ExponentNode < Node
59
- def evaluate(engine)
60
- left.evaluate(engine) ** right.evaluate(engine)
61
- end
62
- end
63
- class ModulusNode < Node
64
- def evaluate(engine)
65
- left.evaluate(engine) % right.evaluate(engine)
66
- end
67
- end
68
-
69
- class FunctionCallNode < Node
70
- def evaluate(engine)
71
- parameters = right ? right.to_a.collect { |p| p.evaluate(engine) } : []
72
- engine.call(left, *parameters)
73
- end
74
- end
35
+ class FunctionCallNode < Node ; end
75
36
 
76
37
  class ParametersNode < Node
77
- def evaluate(engine)
78
- left.evaluate(engine)
79
- end
80
-
81
38
  def to_a
82
39
  [left] + (right ? right.to_a : [])
83
40
  end
data/lib/parser.rb CHANGED
@@ -2,101 +2,101 @@ require File.expand_path(File.join(File.dirname(__FILE__), 'nodes'))
2
2
 
3
3
  class MathEngine
4
4
  class Parser
5
- def initialize(lexer)
6
- @lexer = lexer
7
- end
8
-
9
- def parse
10
- #statement = { <identifier> <assignment> } expression <end>
11
- #expression = term { ( <addition> | <subtraction> ) term }
12
- #term = exp { ( <multiplication> | <division> ) exp }
13
- #exp = factor { ( <exponent> | <modulus> ) factor }
14
- #factor = <call> | <identifier> | <number> | ( <open_parenthesis> expression <close_parenthesis> )
5
+ def initialize(lexer)
6
+ @lexer = lexer
7
+ end
8
+
9
+ def parse
10
+ #statement = { <identifier> <assignment> } expression <end>
11
+ #expression = term { ( <addition> | <subtraction> ) term }
12
+ #term = exp { ( <multiplication> | <division> ) exp }
13
+ #exp = factor { ( <exponent> | <modulus> ) factor }
14
+ #factor = <call> | <identifier> | <number> | ( <open_parenthesis> expression <close_parenthesis> )
15
15
  #call = <identifier> <open_parenthesis> { call_parameter } <close_parenthesis>
16
16
  #call_parameter = <expression> { <comma> call_parameter }
17
- statement
18
- end
19
-
20
- private
17
+ statement
18
+ end
19
+
20
+ private
21
+
22
+ def statement
23
+ next!
24
+ if current.type == :identifier && peek.type == :assignment
25
+ variable_name = current.value
26
+ next!
27
+ expect_current :assignment
28
+ next!
29
+ result = MathEngine::AssignmentNode.new(MathEngine::IdentifierNode.new(variable_name), expression)
30
+ else
31
+ result = expression
32
+ end
33
+ next!
34
+ expect_current :end
35
+ result
36
+ end
37
+
38
+ def expression
39
+ left = term
40
+ result = nil
41
+ while [:addition, :subtraction].include? current.type
42
+ node_type = current.type == :addition ? MathEngine::AdditionNode : MathEngine::SubtractionNode
43
+ next!
44
+ left = node_type.new(left, term)
45
+ end
46
+ result = MathEngine::ExpressionNode.new(result || left)
47
+ result
48
+ end
49
+
50
+ def term
51
+ left = exp
52
+ result = nil
53
+ while [:multiplication, :division].include? current.type
54
+ node_type = current.type == :multiplication ? MathEngine::MultiplicationNode : MathEngine::DivisionNode
55
+ next!
56
+ left = node_type.new(left, exp)
57
+ end
58
+ result || left
59
+ end
21
60
 
22
- def statement
23
- next!
24
- if current.type == :identifier && peek.type == :assignment
25
- variable_name = current.value
26
- next!
27
- expect_current :assignment
28
- next!
29
- result = MathEngine::AssignmentNode.new(MathEngine::IdentifierNode.new(variable_name), expression)
30
- else
31
- result = expression
32
- end
33
- next!
34
- expect_current :end
35
- result
36
- end
37
-
38
- def expression
39
- left = term
40
- result = nil
41
- while [:addition, :subtraction].include? current.type
42
- node_type = current.type == :addition ? MathEngine::AdditionNode : MathEngine::SubtractionNode
43
- next!
44
- left = node_type.new(left, term)
45
- end
46
- result = MathEngine::ExpressionNode.new(result || left)
47
- result
48
- end
49
-
50
- def term
51
- left = exp
52
- result = nil
53
- while [:multiplication, :division].include? current.type
54
- node_type = current.type == :multiplication ? MathEngine::MultiplicationNode : MathEngine::DivisionNode
55
- next!
56
- left = node_type.new(left, exp)
57
- end
58
- result || left
59
- end
60
-
61
- def exp
62
- left = factor
63
- result = nil
64
- while [:exponent, :modulus].include? current.type
65
- node_type = current.type == :exponent ? MathEngine::ExponentNode : MathEngine::ModulusNode
66
- next!
67
- left = node_type.new(left, factor)
68
- end
69
- result || left
61
+ def exp
62
+ left = factor
63
+ result = nil
64
+ while [:exponent, :modulus].include? current.type
65
+ node_type = current.type == :exponent ? MathEngine::ExponentNode : MathEngine::ModulusNode
66
+ next!
67
+ left = node_type.new(left, factor)
68
+ end
69
+ result || left
70
70
  end
71
-
72
- def factor
73
- if current.type == :number
74
- result = MathEngine::LiteralNumberNode.new(current.value)
75
- next!
76
- return result
77
- elsif current.type == :identifier
78
- result = peek.type == :open_parenthesis ? call : MathEngine::IdentifierNode.new(current.value)
71
+
72
+ def factor
73
+ if current.type == :number
74
+ result = MathEngine::LiteralNumberNode.new(current.value)
75
+ next!
76
+ return result
77
+ elsif current.type == :identifier
78
+ result = peek.type == :open_parenthesis ? call : MathEngine::IdentifierNode.new(current.value)
79
79
  next!
80
80
  return result
81
81
  end
82
82
 
83
- expect_current :open_parenthesis, "number, variable or open_parenthesis"
84
- next!
85
- result = expression
86
- expect_current :close_parenthesis
87
- next!
88
- result
89
- end
90
-
91
- def call
92
- expect_current :identifier
93
- function_name = current.value
94
- next!
95
- expect_current :open_parenthesis
96
- next!
97
- result = MathEngine::FunctionCallNode.new(function_name, current.type == :close_parenthesis ? nil : call_parameter)
98
- expect_current :close_parenthesis
99
- result
83
+ expect_current :open_parenthesis, "number, variable or open_parenthesis"
84
+ next!
85
+ result = expression
86
+ expect_current :close_parenthesis
87
+ next!
88
+ result
89
+ end
90
+
91
+ def call
92
+ expect_current :identifier
93
+ function_name = current.value
94
+ next!
95
+ expect_current :open_parenthesis
96
+ next!
97
+ result = MathEngine::FunctionCallNode.new(function_name, current.type == :close_parenthesis ? nil : call_parameter)
98
+ expect_current :close_parenthesis
99
+ result
100
100
  end
101
101
 
102
102
  def call_parameter
@@ -108,21 +108,21 @@ class MathEngine
108
108
  end
109
109
  MathEngine::ParametersNode.new(left, right)
110
110
  end
111
-
112
- def current
113
- @lexer.current
111
+
112
+ def current
113
+ @lexer.current
114
114
  end
115
115
 
116
116
  def peek
117
117
  @lexer.peek
118
118
  end
119
-
120
- def next!
121
- @lexer.next
122
- end
123
-
124
- def expect_current(type, friendly = nil)
125
- raise MathEngine::ParseError.new("Unexpected #{current}, expected: #{friendly ? friendly : type}") unless current.type == type
119
+
120
+ def next!
121
+ @lexer.next
122
+ end
123
+
124
+ def expect_current(type, friendly = nil)
125
+ raise MathEngine::ParseError.new("Unexpected #{current}, expected: #{friendly ? friendly : type}") unless current.type == type
126
126
  end
127
127
  end
128
128
  end
metadata CHANGED
@@ -1,102 +1,91 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: math_engine
3
- version: !ruby/object:Gem::Version
4
- hash: 23
5
- prerelease: false
6
- segments:
7
- - 0
8
- - 2
9
- - 0
10
- version: 0.2.0
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.6.0
5
+ prerelease:
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Michael Baldry
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2010-12-02 00:00:00 +00:00
19
- default_executable:
20
- dependencies:
21
- - !ruby/object:Gem::Dependency
12
+ date: 2012-09-10 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
22
15
  name: lexr
23
- prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
25
17
  none: false
26
- requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- hash: 19
30
- segments:
31
- - 0
32
- - 2
33
- - 2
34
- version: 0.2.2
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 0.3.0
35
22
  type: :runtime
36
- version_requirements: *id001
37
- - !ruby/object:Gem::Dependency
38
- name: rspec
39
23
  prerelease: false
40
- requirement: &id002 !ruby/object:Gem::Requirement
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 0.3.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: rspec
32
+ requirement: !ruby/object:Gem::Requirement
41
33
  none: false
42
- requirements:
43
- - - ">="
44
- - !ruby/object:Gem::Version
45
- hash: 3
46
- segments:
47
- - 0
48
- version: "0"
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
49
38
  type: :development
50
- version_requirements: *id002
51
- description:
52
- email: michael.baldry@uswitch.com
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: Lightweight matematical expression parser that is easy to extend
47
+ email: michael@brightbits.co.uk
53
48
  executables: []
54
-
55
49
  extensions: []
56
-
57
- extra_rdoc_files:
50
+ extra_rdoc_files:
58
51
  - README.md
59
- files:
52
+ files:
60
53
  - README.md
54
+ - lib/context.rb
61
55
  - lib/errors.rb
56
+ - lib/evaluators/calculate.rb
57
+ - lib/evaluators/finders.rb
62
58
  - lib/lexer.rb
63
59
  - lib/math_engine.rb
64
60
  - lib/nodes.rb
65
61
  - lib/parser.rb
66
- has_rdoc: true
67
- homepage: http://www.forwardtechnology.co.uk
62
+ homepage: http://www.brightbits.co.uk
68
63
  licenses: []
69
-
70
64
  post_install_message:
71
- rdoc_options:
65
+ rdoc_options:
72
66
  - --main
73
67
  - README.md
74
- require_paths:
68
+ require_paths:
75
69
  - lib
76
- required_ruby_version: !ruby/object:Gem::Requirement
70
+ required_ruby_version: !ruby/object:Gem::Requirement
77
71
  none: false
78
- requirements:
79
- - - ">="
80
- - !ruby/object:Gem::Version
81
- hash: 3
82
- segments:
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ segments:
83
77
  - 0
84
- version: "0"
85
- required_rubygems_version: !ruby/object:Gem::Requirement
78
+ hash: 4003661917995291831
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
80
  none: false
87
- requirements:
88
- - - ">="
89
- - !ruby/object:Gem::Version
90
- hash: 3
91
- segments:
92
- - 0
93
- version: "0"
81
+ requirements:
82
+ - - ! '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
94
85
  requirements: []
95
-
96
86
  rubyforge_project:
97
- rubygems_version: 1.3.7
87
+ rubygems_version: 1.8.24
98
88
  signing_key:
99
89
  specification_version: 3
100
- summary: Evaluates mathematical expressions
90
+ summary: Lightweight mathematical expression parser
101
91
  test_files: []
102
-