<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -1,7 +1,7 @@
 module TireSwing
   class ParseError &lt; StandardError
     attr_reader :parser
-    def initialize(message, parser)
+    def initialize(message, parser=nil)
       @parser = parser
       super(message)
     end</diff>
      <filename>lib/tire_swing/error.rb</filename>
    </modified>
    <modified>
      <diff>@@ -15,12 +15,9 @@ module TireSwing
         attribs.each do |attrib|
           case attrib
           when Symbol, String
-            attribute(attrib.to_s) { raise &quot;no value given for #{attrib}&quot; }
+            add_mapping(attrib, attrib)
           when Hash
-            attrib.each do |name, symbol|
-              attribute(name.to_s) { raise &quot;no value given for #{name}&quot; }
-              attribute_mapping[name.to_s] = symbol
-            end
+            attrib.each { |name, symbol| add_mapping(name, symbol) }
           end
         end
       end
@@ -31,6 +28,12 @@ module TireSwing
       @attribute_mapping ||= {}
     end
 
+    def self.add_mapping(name, value)
+      attribute(name.to_s) { raise &quot;no value given for #{name}&quot; }
+      attribute_mapping[name.to_s] = value
+    end
+
+    # keep track of where this node lives in the tree
     attr_accessor :parent
 
     # Instantiate a node.
@@ -56,13 +59,9 @@ module TireSwing
     protected
 
     # Auto-builds this node using the provided parsed node and the defined attributes and mapped attributes.
-    def build_from_parsed_node(parsed_node)
+    def build_from_parsed_node(node)
       attributes.each do |attrib|
-        if handler = mapping(attrib)
-          value = apply_mapping(handler, parsed_node)
-        else
-          value = parsed_node.send(attrib)
-        end
+        value = apply_mapping(attrib, node)
 
         value = if value.kind_of?(Array)
           value.map { |val| extract_value(val) }
@@ -74,18 +73,28 @@ module TireSwing
       end
     end
 
-    def apply_mapping(handler, parsed_node)
-      # TODO add in handler for arrays of methods to call in order
+    def apply_mapping(attrib, node)
+      handler = mapping_for(attrib)
+
       if handler.kind_of?(Proc)
-        value = handler.call(parsed_node)
+        value = handler.call(node)
       else
-        # TODO need to add more error checking
-        if parsed_node.respond_to?(handler)
-          value = parsed_node.send(handler)
-        else
-          value = parsed_node.text_value.send(handler)
-        end
+        send_handler_method handler, node
+      end
+
+    end
+
+    def send_handler_method(handler, node)
+      if node.respond_to?(handler)
+        value = node.send(handler)
+      else
+        value = node.text_value.send(handler)
       end
+    rescue NoMethodError
+      context = node.text_value.split(&quot;\n&quot;)
+      context = context.size &gt; 1 ? context.first + &quot;...&quot; : context
+      raise ParseError,
+        %Q{expected node containing &quot;#{context}&quot; or its text value to respond to  #{handler.inspect}}
     end
 
     def extract_value(value)
@@ -104,7 +113,7 @@ module TireSwing
       self.class.attributes
     end
 
-    def mapping(name)
+    def mapping_for(name)
       self.class.attribute_mapping[name]
     end
 </diff>
      <filename>lib/tire_swing/node.rb</filename>
    </modified>
    <modified>
      <diff>@@ -6,6 +6,14 @@ describe TireSwing::ParseError do
     it &quot;takes a message and a parser instance&quot; do
       TireSwing::ParseError.new(&quot;message&quot;, &quot;parser&quot;).should be_an_instance_of(TireSwing::ParseError)
     end
+
+    it &quot;does not require a parser instance&quot; do
+      TireSwing::ParseError.new(&quot;message&quot;).message.should == &quot;message&quot;
+    end
+  end
+
+  it &quot;is a subclass of StandardError&quot; do
+    TireSwing::ParseError.new(&quot;message&quot;, &quot;parser&quot;).should be_a_kind_of(StandardError)
   end
 
   it &quot;has a message&quot; do</diff>
      <filename>spec/error_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -48,11 +48,6 @@ describe TireSwing::Node 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
@@ -63,11 +58,6 @@ describe TireSwing::Node do
       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
@@ -153,6 +143,28 @@ describe TireSwing::Node do
         end
       end
 
+      describe &quot;for a node lacking the required named attribute&quot; do
+        it &quot;raises a parse exception including the text value of the node&quot; do
+          node = TireSwing::Node.create :foo
+          @top.should_receive(:foo).and_raise(NoMethodError.new(&quot;undefined method `foo'...&quot;))
+          @top.stub!(:text_value).and_return(&quot;value&quot;)
+          lambda do
+            node.new(@top)
+          end.should raise_error(TireSwing::ParseError, /expected.*&quot;value&quot;.*foo/)
+        end
+      end
+
+      describe &quot;for a node lacking the defined method for a name/method mapping&quot; do
+        it &quot;raises an exception including the text value of the node&quot; do
+          node = TireSwing::Node.create :foo =&gt; :bar
+          @top.should_receive(:bar).and_raise(NoMethodError.new(&quot;undefined method `bar'...&quot;))
+          @top.stub!(:text_value).and_return(&quot;value&quot;)
+          lambda do
+            node.new(@top)
+          end.should raise_error(TireSwing::ParseError, /expected.*&quot;value&quot;.*bar/)
+        end
+      end
+
     end
   end
 </diff>
      <filename>spec/node_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -70,7 +70,7 @@ end
 
     describe &quot;with invalid input&quot; do
 
-      it &quot;raises an exception with&quot; do
+      it &quot;raises an exception with the parsing error&quot; do
         lambda { parse }.should raise_error(TireSwing::ParseError, /as3f.*\^/m)
       end
 </diff>
      <filename>spec/parser_extension_spec.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>4338421e276a054e8d174cd9ac0093230d29b4a8</id>
    </parent>
  </parents>
  <author>
    <name>Nathan Witmer</name>
    <email>nwitmer@gmail.com</email>
  </author>
  <url>http://github.com/aniero/tire_swing/commit/a223d5c935133db673a11e5115588f05145d60d9</url>
  <id>a223d5c935133db673a11e5115588f05145d60d9</id>
  <committed-date>2008-12-05T16:40:05-08:00</committed-date>
  <authored-date>2008-12-05T16:20:19-08:00</authored-date>
  <message>Added error handling for NoMethodErrors when building the AST</message>
  <tree>097c2eb7d1ddb59eefe09f569eba169579209c5b</tree>
  <committer>
    <name>Nathan Witmer</name>
    <email>nwitmer@gmail.com</email>
  </committer>
</commit>
