<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -17,7 +17,6 @@ spec/grammars/assignments.treetop
 spec/grammars/dot_xen.rb
 spec/grammars/dot_xen.treetop
 spec/grammars/magic.rb
-spec/grammars/magic.treetop
 spec/integration/assignments_spec.rb
 spec/integration/dot_xen_spec.rb
 spec/integration/magic_spec.rb</diff>
      <filename>Manifest.txt</filename>
    </modified>
    <modified>
      <diff>@@ -10,7 +10,7 @@ class Object
   end
 
   # Defines an instance method within a class
-  def class_def name, &amp;blk
-    class_eval { define_method name, &amp;blk }
-  end
+  # def class_def name, &amp;blk
+  #   class_eval { define_method name, &amp;blk }
+  # end
 end</diff>
      <filename>lib/treehouse/metaid.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,8 @@
 module Treehouse
   class Node
 
+    # Create a new node class with the given attributes.
+    # 
     def self.create(*attribs)
       Class.new(self) do
         attribs.each do |attrib|
@@ -21,6 +23,9 @@ module Treehouse
       @attribute_mapping ||= {}
     end
 
+    # Instantiate a new AST node.
+    # Values can either be a hash of values (simple case) or a Treetop syntax node instance (automatic building)
+    # 
     def initialize(values={})
       if values.kind_of?(Treetop::Runtime::SyntaxNode)
         build_from_parsed_node(values)
@@ -35,17 +40,11 @@ module Treehouse
 
     def build_from_parsed_node(parsed_node)
       attributes.each do |attrib|
-        if mapping(attrib)
-          value = parsed_node.send(mapping(attrib))
-          if value.kind_of?(Array)
-            value = value.map { |v| v.build }
-          else
-            value = parsed_node.send(mapping(attrib))
-          end
-          send(&quot;#{attrib}=&quot;, value)
-        else
-          send(&quot;#{attrib}=&quot;, parsed_node.send(attrib).build)
-        end
+        # TODO handle lambda mappings for even more customizability
+        value = mapping(attrib) ? parsed_node.send(mapping(attrib)) : parsed_node.send(attrib)
+        value = value.map { |val| val.respond_to?(:build) ? val.build : val } if value.kind_of?(Array)
+        value = value.build if value.respond_to?(:build)
+        send(&quot;#{attrib}=&quot;, value)
       end
     end
 </diff>
      <filename>lib/treehouse/node.rb</filename>
    </modified>
    <modified>
      <diff>@@ -9,11 +9,9 @@ module Treehouse
       parsed_node = Treetop::Runtime::SyntaxNode.new(*args)
 
       node_class = @node_class # local scope for the block below
-      parsed_node.meta_eval do
-        # TODO don't define this method if it already exists (e.g. inline eval, etc.)
-        define_method :build do
-          node_class.new(self)
-        end
+      # TODO don't define this method if it already exists (e.g. inline eval, etc.)
+      parsed_node.meta_def :build do
+        node_class.new(self)
       end
 
       parsed_node</diff>
      <filename>lib/treehouse/node_creator.rb</filename>
    </modified>
    <modified>
      <diff>@@ -13,9 +13,7 @@ describe Treehouse::Node do
       before(:each) do
         @node = Treehouse::Node.create(:foo, :bar)
       end
-      it &quot;returns a class&quot; do
-        @node.should be_an_instance_of(Class)
-      end
+
       it &quot;creates a class with the given attributes&quot; do
         n = @node.new(:foo =&gt; 1, :bar =&gt; 2)
         n.foo.should == 1
@@ -30,6 +28,98 @@ describe Treehouse::Node do
 
     end
 
+    describe &quot;with an attribute hash&quot; do
+      before(:each) do
+        @node = Treehouse::Node.create(:lhs =&gt; :left_value, :rhs =&gt; :right_value)
+      end
+
+      it &quot;creates a class with attributes matching the hash keys&quot; do
+        @node.attributes.should == [&quot;lhs&quot;, &quot;rhs&quot;]
+      end
+
+      it &quot;creates attributes with a default of raising an exception if not set&quot; do
+        n = @node.new
+        lambda { n.lhs }.should raise_error(RuntimeError, &quot;no value given for lhs&quot;)
+      end
+
+      it &quot;returns a class with an attribute mapping&quot; do
+        @node.attribute_mapping.should == {&quot;lhs&quot; =&gt; :left_value, &quot;rhs&quot; =&gt; :right_value}
+      end
+
+    end
+
+    describe &quot;with a mix of named attributes and hash attributes&quot; do
+      before(:each) do
+        @node = Treehouse::Node.create(:one, :two, :three =&gt; :value)
+      end
+
+      it &quot;creates a class with attributes matching the named attributes and hash keys&quot; do
+        @node.attributes.should == %w(one two three)
+      end
+
+      it &quot;updates the attribute mapping&quot; do
+        @node.attribute_mapping.should == {&quot;three&quot; =&gt; :value}
+      end
+
+    end
+
+  end
+
+  describe &quot;.new&quot; do
+    before(:each) do
+      @node = Treehouse::Node.create(:child, :value =&gt; :data)
+    end
+
+    describe &quot;with empty args&quot; do
+      it &quot;initializes a node without touching the attributes&quot; do
+        n = @node.new
+        lambda { n.child }.should raise_error(RuntimeError)
+      end
+    end
+
+    describe &quot;with a hash&quot; do
+      it &quot;initializes each of the attributes to the given value&quot; do
+        n = @node.new(:child =&gt; 1, :value =&gt; 2)
+        n.child.should == 1
+        n.value.should == 2
+      end
+    end
+
+    describe &quot;with an instance of Treetop::Runtime::SyntaxNode&quot; do
+      before(:each) do
+        @child = mock_syntax_node :build =&gt; &quot;child value&quot;
+        @top = mock_syntax_node :child =&gt; @child, :data =&gt; &quot;data&quot;
+      end
+
+      it &quot;sets the named values by calling build on the named child node&quot; do
+        @top.should_receive(:child).and_return(@child)
+        @child.should_receive(:build).and_return(&quot;child value&quot;)
+        n = @node.new(@top)
+        n.child.should == &quot;child value&quot;
+      end
+
+      it &quot;calls the specified method directly for hash values&quot; do
+        @top.should_receive(:data).and_return do
+          puts &quot;called from #{caller.detect {|c| c !~ /rspec/}}&quot;
+          &quot;foo&quot;
+        end
+        n = @node.new(@top)
+        n.value.should == &quot;foo&quot;
+      end
+
+      it &quot;calls build on each element of a referenced node value if that value is an array&quot; do
+        @top.should_receive(:child).and_return([@child, @child])
+        @child.should_receive(:build).exactly(2).times.and_return(&quot;one&quot;, &quot;two&quot;)
+        n = @node.new(@top)
+        n.child.should == %w(one two)
+      end
+
+      it &quot;only calls build on elements of an array if they respond to that method&quot; do
+        @top.should_receive(:child).and_return([@child, &quot;blah&quot;])
+        @node.new(@top).child.should == [&quot;child value&quot;, &quot;blah&quot;]
+      end
+
+    end
   end
 
 end</diff>
      <filename>spec/node_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -9,4 +9,26 @@ Spec::Runner.configure do |config|
   # config.mock_with :mocha
   # config.mock_with :flexmock
   # config.mock_with :rr
+
+  # borrowed from rspec_on_rails' mock_model
+  def mock_syntax_node(stubs={})
+    m = mock &quot;mock syntax node&quot;, stubs
+    m.send(:__mock_proxy).instance_eval do
+      def @target.is_a?(other)
+        Treetop::Runtime::SyntaxNode.ancestors.include?(other)
+      end
+      def @target.kind_of?(other)
+        Treetop::Runtime::SyntaxNode.ancestors.include?(other)
+      end
+      def @target.instance_of?(other)
+        other == Treetop::Runtime::SyntaxNode
+      end
+      def @target.class
+        Treetop::Runtime::SyntaxNode
+      end
+    end
+    yield m if block_given?
+    m
+  end
+
 end</diff>
      <filename>spec/spec_helper.rb</filename>
    </modified>
    <modified>
      <diff>@@ -18,7 +18,7 @@ PROJ = OpenStruct.new(
   :email =&gt; nil,
   :url =&gt; &quot;\000&quot;,
   :version =&gt; ENV['VERSION'] || '0.0.0',
-  :exclude =&gt; %w(tmp$ bak$ ~$ CVS \.svn/ \.git/ ^pkg/ \.tmproj$),
+  :exclude =&gt; %w(tmp$ bak$ ~$ CVS \.svn/ \.git/ ^pkg/ \.tmproj$ ^coverage/),
   :release_name =&gt; ENV['RELEASE'],
 
   # System Defaults</diff>
      <filename>tasks/setup.rb</filename>
    </modified>
    <modified>
      <diff>@@ -26,7 +26,7 @@ namespace :spec do
     Spec::Rake::SpecTask.new(:rcov) do |t|
       t.ruby_opts = PROJ.ruby_opts
       t.spec_opts = PROJ.spec.opts
-      t.spec_files = PROJ.spec.files
+      t.spec_files = PROJ.spec.files.select { |f| f !~ /integration/ }
       t.libs += PROJ.libs
       t.rcov = true
       t.rcov_dir = PROJ.rcov.dir</diff>
      <filename>tasks/spec.rake</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>edd9f5038a0efa7528d7eaa56b2e4aca4e842c23</id>
    </parent>
  </parents>
  <author>
    <name>Nathan Witmer</name>
    <email>nwitmer@gmail.com</email>
  </author>
  <url>http://github.com/aniero/tire_swing/commit/7bb7169e7745a5a59566d16f30888df843789f0e</url>
  <id>7bb7169e7745a5a59566d16f30888df843789f0e</id>
  <committed-date>2008-07-09T22:40:27-07:00</committed-date>
  <authored-date>2008-07-09T22:40:27-07:00</authored-date>
  <message>Added node specs

* mock_syntax_node helper for convenience
* simplified node building from a parsed node</message>
  <tree>4f9ed53093095969a216b33d861ae8526682d4de</tree>
  <committer>
    <name>Nathan Witmer</name>
    <email>nwitmer@gmail.com</email>
  </committer>
</commit>
