Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Refactor properly to using classes for Nodes

* Improve spec coverage, too
  • Loading branch information...
commit 2cf56dbe869b8b86390d94258d19292e18d2956f 1 parent dbcb6da
@namelessjon authored
View
11 lib/exalted_math.rb
@@ -2,9 +2,12 @@
# Jonathan D. Stott <jonathan.stott@gmail.com>
require 'treetop/runtime'
require 'exalted_math/math'
-require 'exalted_math/ast'
+require 'exalted_math/node'
-module Exalted
+module ExaltedMath
+
+ class ContextError < StandardError; end
+ class ParseFailedError < StandardError; end
class MathsParser
def ast(text)
txt = text.dup
@@ -12,9 +15,9 @@ def ast(text)
txt.gsub!(/\s+/," ")
result = parse(txt)
if result
- [true, result.ast]
+ result.ast
else
- [false, failure_reason]
+ raise ParseFailedError, failure_reason
end
end
end
View
158 lib/exalted_math/ast.rb
@@ -1,158 +0,0 @@
-#!/usr/bin/ruby
-# Jonathan D. Stott <jonathan.stott@gmail.com>
-module ExaltedMath
- class Node
- def initialize(*)
- end
-
- def constant?
- true
- end
-
- def value(context={})
- nil
- end
-
- def simplify
- self
- end
- end
-
- class NumberNode < Node
- def initialize(value)
- @value = value
- end
-
- def constant?
- true
- end
-
- def value(context={})
- @value
- end
- end
-
- class NamedNode < Node
- attr_reader :name
- def initialize(name)
- @name = name
- end
-
- def constant?
- false
- end
-
- def value(context={})
- context.fetch(name) { raise ContextError, name }
- end
- end
-
- class StatNode < NamedNode
- end
-
- class SpecNode < NamedNode
- end
-
- class OperatorNode < Node
- attr_reader :left, :right
-
- def initialize(left, right)
- @left = left
- @right = right
- end
-
- def constant?
- left.constant? and right.constant?
- end
-
- def value(context={})
- raise NotImplementedError
- end
-
- def simplify
- if constant?
- NumberNode.new(value)
- else
- self.class.new(left.simplify, right.simplify)
- end
- end
- end
-
- class AddNode < OperatorNode
- def value(context={})
- left.value(context) + right.value(context)
- end
- end
-
- class SubtractNode < OperatorNode
- def value(context={})
- left.value(context) - right.value(context)
- end
- end
-
- class MultiplyNode < OperatorNode
- def value(context={})
- left.value(context) * right.value(context)
- end
- end
-
- class DivideNode < OperatorNode
- def value(context={})
- left.value(context) / right.value(context)
- end
- end
-
- class ListNode < Node
- attr_reader :nodes
-
- def initialize(nodes=[],*)
- @nodes = nodes
- end
-
- def constant?
- nodes.all? { |n| n.constant? }
- end
-
- def values(context={})
- nodes.map { |node| node.value(context) }
- end
-
- def value(context={})
- values(context).inject(0) { |total, value| total += value }
- end
-
- def simplify
- if constant?
- NumberNode.new(value)
- else
- self
- end
- end
- end
-
- class MaximumNode < ListNode
- attr_reader :count
-
- def initialize(nodes=[],count)
- super
- @count = count
- end
-
- def values(context={})
- nodes.map { |node| node.value(context) }.sort.slice(-count, count)
- end
- end
-
- class MinimumNode < ListNode
- attr_reader :count
-
- def initialize(nodes=[],count)
- super
- @count = count
- end
-
- def values(context={})
- nodes.map { |node| node.value(context) }.sort.slice(0, count)
- end
- end
-end
View
18 lib/exalted_math/math.rb
@@ -25,7 +25,7 @@ def additive
module Additive1
def ast
- AddNode.new(multitive.ast, additive.ast )
+ Node::Add.new(multitive.ast, additive.ast )
end
end
@@ -45,7 +45,7 @@ def additive
module Additive3
def ast
- SubtractNode.new( multitive.ast, additive.ast )
+ Node::Subtract.new( multitive.ast, additive.ast )
end
end
@@ -156,7 +156,7 @@ def multitive
module Multitive1
def ast
- MultiplyNode.new(primary.ast, multitive.ast )
+ Node::Multiply.new(primary.ast, multitive.ast )
end
end
@@ -176,7 +176,7 @@ def multitive
module Multitive3
def ast
- MultiplyNode.new( primary.ast, multitive.ast )
+ Node::Divide.new( primary.ast, multitive.ast )
end
end
@@ -395,7 +395,7 @@ def value
end
def ast
- SpecNode.new(value)
+ Node::Spec.new(value)
end
end
@@ -532,7 +532,7 @@ def count
end
def ast
- MaximumNode.new(list.asts, count)
+ Node::Maximum.new(list.asts, count)
end
end
@@ -677,7 +677,7 @@ def count
end
end
def ast
- MinimumNode.new(list.asts, count)
+ Node::Minimum.new(list.asts, count)
end
end
@@ -965,7 +965,7 @@ def neg
(negative.elements) ? -1 : 1
end
def ast
- NumberNode.new(value)
+ Node::Number.new(value)
end
end
@@ -1054,7 +1054,7 @@ def value
statistic.text_value.downcase
end
def ast
- StatNode.new(value)
+ Node::Stat.new(value)
end
end
View
18 lib/exalted_math/math.treetop
@@ -4,12 +4,12 @@ grammar Maths
rule additive
multitive '+' space additive {
def ast
- AddNode.new(multitive.ast, additive.ast )
+ Node::Add.new(multitive.ast, additive.ast )
end
}
/ multitive '-' space additive {
def ast
- SubtractNode.new( multitive.ast, additive.ast )
+ Node::Subtract.new( multitive.ast, additive.ast )
end
}
/ multitive
@@ -18,13 +18,13 @@ grammar Maths
rule multitive
primary '*' space multitive {
def ast
- MultiplyNode.new(primary.ast, multitive.ast )
+ Node::Multiply.new(primary.ast, multitive.ast )
end
}
/
primary '/' space multitive {
def ast
- MultiplyNode.new( primary.ast, multitive.ast )
+ Node::Divide.new( primary.ast, multitive.ast )
end
}
/ primary
@@ -46,7 +46,7 @@ grammar Maths
end
def ast
- SpecNode.new(value)
+ Node::Spec.new(value)
end
}
end
@@ -62,7 +62,7 @@ grammar Maths
end
def ast
- MaximumNode.new(list.asts, count)
+ Node::Maximum.new(list.asts, count)
end
}
end
@@ -77,7 +77,7 @@ grammar Maths
end
end
def ast
- MinimumNode.new(list.asts, count)
+ Node::Minimum.new(list.asts, count)
end
}
end
@@ -114,7 +114,7 @@ grammar Maths
(negative.elements) ? -1 : 1
end
def ast
- NumberNode.new(value)
+ Node::Number.new(value)
end
}
end
@@ -125,7 +125,7 @@ grammar Maths
statistic.text_value.downcase
end
def ast
- StatNode.new(value)
+ Node::Stat.new(value)
end
}
end
View
12 lib/exalted_math/node.rb
@@ -0,0 +1,12 @@
+#!/usr/bin/env ruby
+require 'exalted_math/node/node'
+require 'exalted_math/node/number'
+require 'exalted_math/node/named'
+require 'exalted_math/node/operator'
+require 'exalted_math/node/add'
+require 'exalted_math/node/subtract'
+require 'exalted_math/node/divide'
+require 'exalted_math/node/multiply'
+require 'exalted_math/node/list'
+require 'exalted_math/node/maximum'
+require 'exalted_math/node/minimum'
View
12 lib/exalted_math/node/add.rb
@@ -0,0 +1,12 @@
+#!/usr/bin/env ruby
+require 'exalted_math/node/node'
+require 'exalted_math/node/operator'
+module ExaltedMath
+ class Node
+ class Add < Operator
+ def value(context={})
+ left.value(context) + right.value(context)
+ end
+ end
+ end
+end
View
13 lib/exalted_math/node/divide.rb
@@ -0,0 +1,13 @@
+#!/usr/bin/env ruby
+require 'exalted_math/node/node'
+require 'exalted_math/node/operator'
+module ExaltedMath
+ class Node
+ class Divide < Operator
+ def value(context={})
+ left.value(context) / right.value(context)
+ end
+ end
+ end
+end
+
View
38 lib/exalted_math/node/list.rb
@@ -0,0 +1,38 @@
+#!/usr/bin/env ruby
+require 'exalted_math/node/node'
+module ExaltedMath
+ class Node
+ class List < Node
+ attr_reader :nodes
+
+ def initialize(nodes=[],*)
+ @nodes = nodes
+ end
+
+ def constant?
+ nodes.all? { |n| n.constant? }
+ end
+
+ def values(context={})
+ nodes.map { |node| node.value(context) }
+ end
+
+ def value(context={})
+ values(context).inject(0) { |total, value| total += value }
+ end
+
+ def simplify
+ if constant?
+ Number.new(value)
+ else
+ self
+ end
+ end
+
+ def ==(o)
+ return false unless self.class === o
+ nodes == o.nodes
+ end
+ end
+ end
+end
View
25 lib/exalted_math/node/maximum.rb
@@ -0,0 +1,25 @@
+#!/usr/bin/env ruby
+require 'exalted_math/node/node'
+require 'exalted_math/node/list'
+module ExaltedMath
+ class Node
+ class Maximum < List
+ attr_reader :count
+
+ def initialize(nodes=[],count)
+ super
+ @count = count
+ end
+
+ def values(context={})
+ nodes.map { |node| node.value(context) }.sort.slice(-count, count)
+ end
+
+ def ==(o)
+ return false unless super
+ count == o.count
+ end
+ end
+ end
+end
+
View
24 lib/exalted_math/node/minimum.rb
@@ -0,0 +1,24 @@
+#!/usr/bin/env ruby
+require 'exalted_math/node/node'
+require 'exalted_math/node/list'
+module ExaltedMath
+ class Node
+ class Minimum < List
+ attr_reader :count
+
+ def initialize(nodes=[],count)
+ super
+ @count = count
+ end
+
+ def values(context={})
+ nodes.map { |node| node.value(context) }.sort.slice(0, count)
+ end
+
+ def ==(o)
+ return false unless super
+ count == o.count
+ end
+ end
+ end
+end
View
13 lib/exalted_math/node/multiply.rb
@@ -0,0 +1,13 @@
+#!/usr/bin/env ruby
+require 'exalted_math/node/node'
+require 'exalted_math/node/operator'
+module ExaltedMath
+ class Node
+ class Multiply < Operator
+ def value(context={})
+ left.value(context) * right.value(context)
+ end
+ end
+ end
+end
+
View
36 lib/exalted_math/node/named.rb
@@ -0,0 +1,36 @@
+#!/usr/bin/env ruby
+require 'exalted_math/node/node'
+module ExaltedMath
+ class Node
+ class Named < Node
+ attr_reader :name
+ def initialize(name)
+ @name = name
+ end
+
+ def constant?
+ false
+ end
+
+ def value(context={})
+ context.fetch(name) { raise ContextError, name }
+ end
+
+ def ==(o)
+ return false unless self.class === o
+ self.name == o.name
+ end
+
+ def valid?(stats)
+ stats.include?(name)
+ end
+ end
+
+ class Stat < Named
+ end
+
+ class Spec < Named
+ end
+
+ end
+end
View
23 lib/exalted_math/node/node.rb
@@ -0,0 +1,23 @@
+#!/usr/bin/env ruby
+module ExaltedMath
+ class Node
+ def initialize(*)
+ end
+
+ def constant?
+ true
+ end
+
+ def value(context={})
+ nil
+ end
+
+ def simplify
+ self
+ end
+
+ def valid?(*)
+ false
+ end
+ end
+end
View
28 lib/exalted_math/node/number.rb
@@ -0,0 +1,28 @@
+#!/usr/bin/env ruby
+require 'exalted_math/node/node'
+module ExaltedMath
+ class Node
+ class Number < Node
+ def initialize(value)
+ @value = value
+ end
+
+ def constant?
+ true
+ end
+
+ def value(context={})
+ @value
+ end
+
+ def ==(o)
+ return false unless self.class === o
+ @value == o.value
+ end
+
+ def valid?(*)
+ true
+ end
+ end
+ end
+end
View
39 lib/exalted_math/node/operator.rb
@@ -0,0 +1,39 @@
+#!/usr/bin/env ruby
+require 'exalted_math/node/node'
+module ExaltedMath
+ class Node
+ class Operator < Node
+ attr_reader :left, :right
+
+ def initialize(left, right)
+ @left = left
+ @right = right
+ end
+
+ def constant?
+ left.constant? and right.constant?
+ end
+
+ def value(context={})
+ raise NotImplementedError
+ end
+
+ def simplify
+ if constant?
+ Number.new(value)
+ else
+ self.class.new(left.simplify, right.simplify)
+ end
+ end
+
+ def ==(o)
+ return false unless self.class === o
+ left == o.left && right == o.right
+ end
+
+ def valid?(stats=[])
+ left.valid?(stats) && right.valid?(stats)
+ end
+ end
+ end
+end
View
13 lib/exalted_math/node/subtract.rb
@@ -0,0 +1,13 @@
+#!/usr/bin/env ruby
+require 'exalted_math/node/node'
+require 'exalted_math/node/operator'
+module ExaltedMath
+ class Node
+ class Subtract < Operator
+ def value(context={})
+ left.value(context) - right.value(context)
+ end
+ end
+ end
+end
+
View
207 spec/ast_spec.rb
@@ -1,207 +0,0 @@
-#!/usr/bin/ruby
-# Jonathan D. Stott <jonathan.stott@gmail.com>
-require 'spec_helper'
-require 'exalted_math/ast'
-
-include Exalted
-
-
-describe "Exalted::Ast" do
- before do
- @three = Exalted::Ast.new('num', 3 )
- @seven = Exalted::Ast.new('num', 7 )
- @foo = Exalted::Ast.new('stat', 'foo')
- @bar = Exalted::Ast.new('spec', 'bar')
- @invalid = Exalted::Ast.new('stat', 'invalid')
- @add = Exalted::Ast.new('add', @three, @seven)
- @sub = Exalted::Ast.new('sub', @three, @seven)
- @mul = Exalted::Ast.new('mul', @three, @seven)
- @div = Exalted::Ast.new('div', @seven, @three)
- @add_foo = Exalted::Ast.new('add', @three, @foo)
- @sub_foo = Exalted::Ast.new('sub', @three, @foo)
- @mul_foo = Exalted::Ast.new('mul', @three, @foo)
- @div_foo = Exalted::Ast.new('div', @three, @foo)
- @nested = Exalted::Ast.new('mul', @add, @sub_foo)
- @min = Exalted::Ast.new('min', 1, [@three, @seven] )
- @max = Exalted::Ast.new('max', 1, [@three, @seven] )
- @context = { 'foo' => 3, 'bar' => 4 }
- end
-
- it ".num makes a number" do
- @three.should == Ast.num(3)
- end
-
- it ".stat makes a stat" do
- @foo.should == Ast.stat('foo')
- end
-
- it ".spec makes a spec" do
- @bar.should == Ast.spec('bar')
- end
-
- it ".add makes an add" do
- @add.should == Ast.add(@three, @seven)
- end
-
- it ".sub makes an sub" do
- @sub.should == Ast.sub(@three, @seven)
- end
-
- it ".mul makes an mul" do
- @mul.should == Ast.mul(@three, @seven)
- end
-
- it ".div makes an div" do
- @div.should == Ast.div(@seven, @three)
- end
-
- it ".min makes a min" do
- @min.should == Ast.min(1, [@three, @seven])
- end
-
- it ".max makes a max" do
- @max.should == Ast.max(1, [@three, @seven])
- end
-
- it "a number is constant" do
- @three.should.be.constant
- end
-
- it "a stat is not constant" do
- @foo.should.not.be.constant
- end
-
- it "an add of two constants is constant" do
- @add.should.be.constant
- end
- it "an sub of two constants is constant" do
- @sub.should.be.constant
- end
- it "an mul of two constants is constant" do
- @mul.should.be.constant
- end
- it "an div of two constants is constant" do
- @div.should.be.constant
- end
- it "a min of constants is constant" do
- @min.should.be.constant
- end
- it "a max of constants is constant" do
- @max.should.be.constant
- end
-
- it "an add of constant and not constant is not constant" do
- @add_foo.should.not.be.constant
- end
- it "an sub of constant and not constant is not constant" do
- @sub_foo.should.not.be.constant
- end
- it "an mul of constant and not constant is not constant" do
- @mul_foo.should.not.be.constant
- end
- it "an div of constant and not constant is not constant" do
- @div_foo.should.not.be.constant
- end
-
- it "A number is valid" do
- Exalted::Ast.valid?(@three, @context.keys).should.be.true
- end
-
- it "A stat is valid if it is in the array of valid keys" do
- Exalted::Ast.valid?(@foo, @context.keys).should.be.true
- end
-
- it "A stat is not valid if it is not in the array of valid keys" do
- Exalted::Ast.valid?(@invalid, @context.keys).should.not.be.true
- end
-
- it "An add is valid if both its keys are valid" do
- Exalted::Ast.valid?(@add, @context.keys).should.be.true
- end
- it "An sub is valid if both its keys are valid" do
- Exalted::Ast.valid?(@sub, @context.keys).should.be.true
- end
- it "An mul is valid if both its keys are valid" do
- Exalted::Ast.valid?(@mul, @context.keys).should.be.true
- end
- it "An div is valid if both its keys are valid" do
- Exalted::Ast.valid?(@div, @context.keys).should.be.true
- end
- it "An add is invalid if one key is invalid" do
- @add = Exalted::Ast.new('add', @three, @invalid)
- Exalted::Ast.valid?(@add, @context.keys).should.not.be.true
- end
- it "An sub is invalid if one key is invalid" do
- @sub = Exalted::Ast.new('sub', @three, @invalid)
- Exalted::Ast.valid?(@sub, @context.keys).should.not.be.true
- end
- it "An mul is invalid if one key is invalid" do
- @mul = Exalted::Ast.new('mul', @three, @invalid)
- Exalted::Ast.valid?(@mul, @context.keys).should.not.be.true
- end
- it "An div is invalid if one key is invalid" do
- @div = Exalted::Ast.new('div', @three, @invalid)
- Exalted::Ast.valid?(@div, @context.keys).should.not.be.true
- end
-
- it "the value of a number is the number" do
- Exalted::Ast.value(@three, @context).should == 3
- Exalted::Ast.value(@seven, @context).should == 7
- end
-
- it "the value of a stat is looked up in the context" do
- Exalted::Ast.value(@foo, @context).should == @context['foo']
- Exalted::Ast.value(@bar, @context).should == @context['bar']
- end
-
- it "the value of an add is the sum of the two children" do
- Exalted::Ast.value(@add, @context).should == 10
- end
-
- it "the value of an sub is first child minus the second" do
- Exalted::Ast.value(@sub, @context).should == -4
- end
-
- it "the value of an mul is the two children multiplied together" do
- Exalted::Ast.value(@mul, @context).should == 21
- end
-
- it "the value of a div is the first child divided by the second" do
- Exalted::Ast.value(@div, @context).should == 2
- end
-
- it "the value of a min is the mininum value" do
- Exalted::Ast.value(@min, @context).should == 3
- end
- it "the value of a max is the maxinum value" do
- Exalted::Ast.value(@max, @context).should == 7
- end
-
- it "it walks the whole tree to compute a value" do
- Exalted::Ast.value(@nested, @context).should == 0
- end
-
- it "has sane equality behaviour" do
- @three.should == Exalted::Ast.new('num', 3)
- end
-
- it "can simplify a constant add" do
- Exalted::Ast.simplify(@add).should == Exalted::Ast.new('num', 10)
- end
-
- it "A number is simple" do
- Exalted::Ast.simplify(@three).should == Exalted::Ast.new('num', 3)
- end
-
- it "A stat is simple" do
- Exalted::Ast.simplify(@foo).should == Exalted::Ast.new('stat', 'foo')
- end
-
- it "A non-constant add isn't simplified" do
- Exalted::Ast.simplify(@add_foo).should == Exalted::Ast.new('add', @three, @foo)
- end
- it "A constant branches are simplified" do
- Exalted::Ast.simplify(@nested).should == Exalted::Ast.new('mul', Exalted::Ast.new('num', 10), @sub_foo)
- end
-end
-
View
183 spec/node_spec.rb
@@ -0,0 +1,183 @@
+#!/usr/bin/ruby
+# Jonathan D. Stott <jonathan.stott@gmail.com>
+require 'spec_helper'
+require 'exalted_math/node'
+
+include ExaltedMath
+
+
+describe "ExaltedMath::Node" do
+ before do
+ @three = Node::Number.new(3)
+ @seven = Node::Number.new(7)
+ @foo = Node::Stat.new('foo')
+ @bar = Node::Spec.new('bar')
+ @invalid = Node::Stat.new('invalid')
+ @add = Node::Add.new( @three, @seven)
+ @sub = Node::Subtract.new(@three, @seven)
+ @mul = Node::Multiply.new(@three, @seven)
+ @div = Node::Divide.new(@seven, @three)
+ @add_foo = Node::Add.new(@three, @foo)
+ @sub_foo = Node::Subtract.new(@three, @foo)
+ @mul_foo = Node::Multiply.new(@three, @foo)
+ @div_foo = Node::Divide.new(@three, @foo)
+ @nested = Node::Multiply.new(@add, @sub_foo)
+ @min = Node::Minimum.new([@three, @seven], 1)
+ @max = Node::Maximum.new([@three, @seven], 1 )
+ @context = { 'foo' => 3, 'bar' => 4 }
+ end
+ it "a number is constant" do
+ @three.should.be.constant
+ end
+
+ it "a stat is not constant" do
+ @foo.should.not.be.constant
+ end
+
+ it "an add of two constants is constant" do
+ @add.should.be.constant
+ end
+ it "an sub of two constants is constant" do
+ @sub.should.be.constant
+ end
+ it "an mul of two constants is constant" do
+ @mul.should.be.constant
+ end
+ it "an div of two constants is constant" do
+ @div.should.be.constant
+ end
+ it "a min of constants is constant" do
+ @min.should.be.constant
+ end
+ it "a max of constants is constant" do
+ @max.should.be.constant
+ end
+
+ it "an add of constant and not constant is not constant" do
+ @add_foo.should.not.be.constant
+ end
+ it "an sub of constant and not constant is not constant" do
+ @sub_foo.should.not.be.constant
+ end
+ it "an mul of constant and not constant is not constant" do
+ @mul_foo.should.not.be.constant
+ end
+ it "an div of constant and not constant is not constant" do
+ @div_foo.should.not.be.constant
+ end
+
+ it "A number is valid" do
+ @three.valid?(@context.keys).should.be.true
+ end
+
+ it "A stat is valid if it is in the array of valid keys" do
+ @foo.valid?(@context.keys).should.be.true
+ end
+
+ it "A stat is not valid if it is not in the array of valid keys" do
+ @invalid.valid?(@context.keys).should.not.be.true
+ end
+
+ it "An add is valid if both its keys are valid" do
+ @add.valid?(@context.keys).should.be.true
+ end
+ it "An sub is valid if both its keys are valid" do
+ @sub.valid?(@context.keys).should.be.true
+ end
+ it "An mul is valid if both its keys are valid" do
+ @mul.valid?(@context.keys).should.be.true
+ end
+ it "An div is valid if both its keys are valid" do
+ @div.valid?(@context.keys).should.be.true
+ end
+ it "An add is invalid if one key is invalid" do
+ @add = Node::Add.new(@three, @invalid)
+ @add.valid?(@context.keys).should.not.be.true
+ end
+ it "An sub is invalid if one key is invalid" do
+ @sub = Node::Subtract.new(@three, @invalid)
+ @sub.valid?(@context.keys).should.not.be.true
+ end
+ it "An mul is invalid if one key is invalid" do
+ @mul = Node::Multiply.new(@three, @invalid)
+ @mul.valid?(@context.keys).should.not.be.true
+ end
+ it "An div is invalid if one key is invalid" do
+ @div = Node::Divide.new(@three, @invalid)
+ @div.valid?(@context.keys).should.not.be.true
+ end
+
+ it "the value of a number is the number" do
+ @three.value(@context).should == 3
+ @seven.value(@context).should == 7
+ end
+
+ it "the value of a stat is looked up in the context" do
+ @foo.value(@context).should == @context['foo']
+ @bar.value(@context).should == @context['bar']
+ end
+
+ it "the value of an add is the sum of the two children" do
+ @add.value(@context).should == 10
+ end
+
+ it "the value of an sub is first child minus the second" do
+ @sub.value(@context).should == -4
+ end
+
+ it "the value of an mul is the two children multiplied together" do
+ @mul.value(@context).should == 21
+ end
+
+ it "the value of a div is the first child divided by the second" do
+ @div.value(@context).should == 2
+ end
+
+ it "the value of a min is the mininum value" do
+ @min.value(@context).should == 3
+ end
+ it "the value of a max is the maxinum value" do
+ @max.value(@context).should == 7
+ end
+
+ it "it walks the whole tree to compute a value" do
+ @nested.value(@context).should == 0
+ end
+
+ it "can simplify a constant add" do
+ @add.simplify.should == Node::Number.new(10)
+ end
+
+ it "A number is simple" do
+ @three.simplify.should == Node::Number.new(3)
+ end
+
+ it "A stat is simple" do
+ @foo.simplify.should == Node::Stat.new('foo')
+ end
+
+ it "A non-constant add isn't simplified" do
+ @add_foo.simplify.should == Node::Add.new(@three, @foo)
+ end
+ it "A constant branches are simplified" do
+ @nested.simplify.should == Node::Multiply.new(Node::Number.new(10), @sub_foo)
+ end
+
+
+ node_inequality Node::Number.new(1), Node::Number.new(2)
+ node_inequality Node::Number.new(1), Node::Spec.new('foo')
+ node_inequality Node::Number.new(1), Node::Stat.new('foo')
+ node_inequality Node::Stat.new('bar'), Node::Stat.new('foo')
+ node_inequality Node::Spec.new('foo'), Node::Stat.new('foo')
+ node_inequality Node::Minimum.new([Node::Number.new(1), Node::Stat.new('foo')], 1), Node::Minimum.new([Node::Number.new(1), Node::Stat.new('foo')], 2)
+ node_inequality Node::Maximum.new([Node::Number.new(1), Node::Stat.new('foo')], 1), Node::Maximum.new([Node::Number.new(1), Node::Stat.new('foo')], 2)
+ node_inequality Node::Minimum.new([Node::Number.new(1), Node::Spec.new('foo')], 1), Node::Minimum.new([Node::Number.new(1), Node::Stat.new('foo')], 1)
+ node_inequality Node::Minimum.new([Node::Number.new(1), Node::Spec.new('foo')], 1), Node::Maximum.new([Node::Number.new(1), Node::Spec.new('foo')], 1)
+
+ node_equality Node::Number.new(1), Node::Number.new(1)
+ node_equality Node::Spec.new('foo'), Node::Spec.new('foo')
+ node_equality Node::Stat.new('foo'), Node::Stat.new('foo')
+ node_equality Node::Minimum.new([Node::Number.new(1), Node::Stat.new('foo')], 1), Node::Minimum.new([Node::Number.new(1), Node::Stat.new('foo')], 1)
+ node_equality Node::Maximum.new([Node::Number.new(1), Node::Stat.new('foo')], 1), Node::Maximum.new([Node::Number.new(1), Node::Stat.new('foo')], 1)
+end
+
View
40 spec/parser_spec.rb
@@ -1,45 +1,35 @@
#!/usr/bin/ruby
-# Jonathan D. Stott <jonathan.stott@gmail.com>
require 'spec_helper'
require 'exalted_math'
-include Exalted
+include ExaltedMath
-class ParserFailure < Bacon::Error
- def initialize(failure)
- super :failure, failure
- end
-end
describe "Exalted::MathParser" do
before do
- @parser = Exalted::MathsParser.new
+ @parser = ExaltedMath::MathsParser.new
end
[
- [' 4 ', Ast.num(4)],
- [' -1 ', Ast.num(-1)],
- [' 3 * 4 ', Ast.mul(Ast.num(3), Ast.num(4) )],
- [' 3 - 4 ', Ast.sub(Ast.num(3), Ast.num(4) )],
- [' 3 + 4 ', Ast.add(Ast.num(3), Ast.num(4) )],
- [' 6 / 3 ', Ast.div(Ast.num(6), Ast.num(3) )],
- [' spec:"Beating stuff" ', Ast.spec("Beating stuff")],
- ['Essence * 4', Ast.mul(Ast.stat('essence'), Ast.num(4) )],
- ['(Essence * 4) + Willpower', Ast.add(Ast.mul(Ast.stat('essence'), Ast.num(4) ), Ast.stat('willpower'))],
- ['highest[2](compassion,conviction,temperance,valor)', Ast.max(2, [Ast.stat('compassion'),Ast.stat('conviction'),Ast.stat('temperance'),Ast.stat('valor') ])],
- ['min(compassion,conviction,temperance,valor)', Ast.min(1, [Ast.stat('compassion'),Ast.stat('conviction'),Ast.stat('temperance'),Ast.stat('valor') ])]
+ [' 4 ', Node::Number.new(4)],
+ [' -1 ', Node::Number.new(-1)],
+ [' 3 * 4 ', Node::Multiply.new(Node::Number.new(3), Node::Number.new(4) )],
+ [' 3 - 4 ', Node::Subtract.new(Node::Number.new(3), Node::Number.new(4) )],
+ [' 3 + 4 ', Node::Add.new(Node::Number.new(3), Node::Number.new(4) )],
+ [' 6 / 3 ', Node::Divide.new(Node::Number.new(6), Node::Number.new(3) )],
+ [' spec:"Beating stuff" ', Node::Spec.new("Beating stuff")],
+ ['Essence * 4', Node::Multiply.new(Node::Stat.new('essence'), Node::Number.new(4) )],
+ ['(Essence * 4) + Willpower', Node::Add.new(Node::Multiply.new(Node::Stat.new('essence'), Node::Number.new(4) ), Node::Stat.new('willpower'))],
+ ['highest[2](compassion,conviction,temperance,valor)', Node::Maximum.new([Node::Stat.new('compassion'),Node::Stat.new('conviction'),Node::Stat.new('temperance'),Node::Stat.new('valor') ], 2)],
+ ['min(compassion,conviction,temperance,valor)', Node::Minimum.new([Node::Stat.new('compassion'),Node::Stat.new('conviction'),Node::Stat.new('temperance'),Node::Stat.new('valor') ], 1)]
].each do |string, ast|
it "parses '#{string}'" do
- success, result = @parser.ast(string)
- raise ParserFailure, result unless success
- success.should.be.true
+ result = @parser.ast(string)
result.should == ast
end
end
it "Doesn't care about spaces" do
- success, result = @parser.ast(' ( Essence * 4 ) + Willpower + highest[2]( compassion , conviction ) ')
- raise ParserFailure, result unless success
- success.should.be.true
+ proc { @parser.ast(' ( Essence * 4 ) + Willpower + highest[2]( compassion , conviction ) ') }.should.not.raise(ParseFailedError)
end
end
View
13 spec/spec_helper.rb
@@ -3,3 +3,16 @@
require 'bacon'
Bacon.summary_on_exit
+
+class Bacon::Context
+ def node_inequality(left, right)
+ it "`#{left.inspect}' != `#{right.inspect}`" do
+ left.should.not == right
+ end
+ end
+ def node_equality(left, right)
+ it "`#{left.inspect}' == `#{right.inspect}`" do
+ left.should == right
+ end
+ end
+end

0 comments on commit 2cf56db

Please sign in to comment.
Something went wrong with that request. Please try again.