Permalink
Browse files

Big commit. Changes below. Now requires Ruby 1.9+

* Fix #2
* Fix #20
* Fix #12
  • Loading branch information...
1 parent 797157d commit d41fb531025d0ce7656d7efcafea789d65d8aae5 @Trevoke committed Mar 25, 2012
Showing with 237 additions and 167 deletions.
  1. +1 −1 .rspec
  2. +1 −1 README.rdoc
  3. +2 −8 lib/sgf/game.rb
  4. +48 −19 lib/sgf/node.rb
  5. +13 −13 spec/game_spec.rb
  6. +127 −79 spec/node_spec.rb
  7. +30 −30 spec/parser_spec.rb
  8. +8 −8 spec/tree_spec.rb
  9. +7 −8 spec/writer_spec.rb
View
2 .rspec
@@ -1 +1 @@
---color --format doc
+--color --format doc
View
@@ -7,7 +7,7 @@ Are you using this gem? Is there functionality you wish it had? Is something har
SGF: FF4 - may support earlier ones as well, but untested.
-Ruby: >=1.8.7 (may work with 1.8.6)
+Ruby: >=1.9
WARNING: An implementation requirement is to make sure any closing bracket ']' inside a comment is escaped: '\\]'. If this is not done, you will be one sad panda! This library will do this for you upon saving, but will most likely die horribly when parsing anything which does not follow this rule.
View
@@ -26,12 +26,12 @@ def next_node
#Iterate through all the nodes in preorder fashion
def each &block
- preorder @root, &block
+ @root.each &block
end
def node_count
count = 0
- each { |node| count += 1 }
+ each { count += 1 }
count
end
@@ -54,11 +54,5 @@ def method_missing method_name, *args
super(method_name, args)
end
- def preorder node=@root, &block
- yield node
- node.each_child do |child|
- preorder child, &block
- end
- end
end
end
View
@@ -1,49 +1,67 @@
+require 'set'
module SGF
#Your basic node. It holds information about itself, its parent, and its children.
class Node
- include Observable
+ include Enumerable
- attr_accessor :parent, :children, :properties, :depth
+ attr_accessor :children, :properties, :depth
# Creates a new node. Arguments which can be passed in are:
# :parent => parent_node (nil by default)
# :children => [list, of, children] (empty array if nothing is passed)
# :properties => {hash_of => properties} (empty hash if nothing is passed)
def initialize args={}
+ opts = {children: [], properties: {}, parent: nil}
+ opts.merge! args
@depth = 0
- @parent = args[:parent]
@children = []
- add_children args[:children] if args[:children]
- @properties = Hash.new
- add_properties args[:properties] if args[:properties]
+ set_parent opts[:parent]
+ add_children opts[:children]
+ add_properties opts[:properties]
end
+ def parent
+ @parent
+ end
+
+ def parent= parent
+ return unless parent
+ if @parent
+ @parent.children.delete self
+ end
+ @parent = parent
+ parent.children << self
+ self.each do |node|
+ node.depth = node.parent.depth + 1
+ end
+ end
+
+ alias :set_parent :parent=
+
#Takes an arbitrary number of child nodes, adds them to the list of children, and make this node their parent.
def add_children *nodes
- nodes.flatten!
- raise "Non-node child given!" if nodes.any? { |node| node.class != Node }
- nodes.each do |node|
- if node.parent && node.parent.children
- node.parent.children.delete node
- end
- node.parent = self
- node.depth = @depth + 1
- @children << node
+ nodes.flatten.each do |node|
+ node.parent= self
end
end
#Takes a hash {identity => property} and adds those to the current node.
#If a property already exists, it will append to it.
def add_properties hash
+ @properties ||= {}
hash.each do |identity, property|
@properties[identity] ||= property.class.new
@properties[identity].concat property
end
update_human_readable_methods
end
- #Iterate through each child. Yields a child node, if one exists.
+ def each &block
+ preorder self, &block
+ end
+
+ #Iterate through and yield each child.
def each_child
@children.each { |child| yield child }
end
@@ -80,12 +98,16 @@ def to_str(indent = 0)
def stringify_identity_and_property(identity, property)
new_property = property.instance_of?(Array) ? property.join("][") : property
- new_property = new_property.gsub("]", "\\]") if identity == "C"
+ new_property = new_property.gsub("]", "\\]") if flexible(identity) == "C"
"#{identity.to_s}[#{new_property}]"
end
private
+ def flexible id
+ id.to_s.upcase
+ end
+
def update_human_readable_methods
SGF::Node::PROPERTIES.each do |human_readable_method, sgf_identity|
next if defined? human_readable_method.to_sym
@@ -95,12 +117,19 @@ def update_human_readable_methods
end
end
+ def preorder node=self, &block
+ yield node
+ node.each_child do |child|
+ preorder child, &block
+ end
+ end
+
def leading_whitespace(indent)
"#{" " * indent}"
end
def method_missing method_name, *args
- property = method_name.to_s.upcase
+ property = flexible(method_name)
if property[/(.*?)=$/]
@properties[$1] = args[0]
else
@@ -112,4 +141,4 @@ def method_missing method_name, *args
end
-end
+end
View
@@ -4,7 +4,7 @@
it "should hold the first node of the game" do
game = get_first_game_from 'spec/data/ff4_ex.sgf'
- game.current_node["FF"].should == "4"
+ game.current_node["FF"].should eq "4"
end
it "should throw up if initialized with a non-Node argument" do
@@ -14,8 +14,8 @@
it "should have the expected game-level information" do
game = get_first_game_from 'spec/data/ff4_ex.sgf'
- game.name.should == "Gametree 1: properties"
- game.data_entry.should == "Arno Hollosi"
+ game.name.should eq "Gametree 1: properties"
+ game.data_entry.should eq "Arno Hollosi"
expect { game.opening }.to raise_error(SGF::NoIdentityError)
expect { game.nonexistent_identity }.to raise_error(NoMethodError)
end
@@ -31,20 +31,20 @@
it "should have 'root' as the default current node" do
game = get_first_game_from 'spec/data/ff4_ex.sgf'
- game.current_node.should == game.root
+ game.current_node.should eq game.root
end
it "should have a nice way to go to children[0]" do
game = get_first_game_from 'spec/data/ff4_ex.sgf'
game.next_node
- game.current_node.should == game.root.children[0]
+ game.current_node.should eq game.root.children[0]
end
it "should have a way of setting an arbitrary node to the current node" do
game = get_first_game_from 'spec/data/ff4_ex.sgf'
game.current_node = game.root.children[3]
- game.current_node.properties.keys.sort.should == ["B", "C", "N"]
- game.current_node.children.size.should == 6
+ game.current_node.properties.keys.sort.should eq %w(B C N)
+ game.current_node.children.size.should eq 6
end
end
@@ -53,18 +53,18 @@
game = get_first_game_from 'spec/data/example1.sgf'
array = []
game.each { |node| array << node }
- array[0].c.should == "root"
- array[1].c.should == "a"
- array[2].c.should == "b"
+ array[0].c.should eq "root"
+ array[1].c.should eq "a"
+ array[2].c.should eq "b"
end
it "should go through all nodes, even if block returns 'nil' (puts, anyone?)" do
- root = SGF::Node.new :properties => {"FF" => "4", "PB" => "Me", "PW" => "You"}
+ root = SGF::Node.new :properties => {FF: "4", PB: "Me", PW: "You"}
game = SGF::Game.new root
- root.add_children SGF::Node.new(:properties => {"B" => "dd"})
+ root.add_children SGF::Node.new(:properties => {B: "dd"})
nodes = []
game.each { |node| nodes << node; nil }
- nodes.size.should == 2
+ nodes.size.should eq 2
end
end
Oops, something went wrong.

0 comments on commit d41fb53

Please sign in to comment.