aniero-tire_swing 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,9 @@
1
+ == 0.0.6 / 2008-12-05
2
+
3
+ * 2 minor enhancements
4
+ * activesupport "compatibility mode" to work around extlib inflections messing with rails
5
+ * Added error handling for NoMethodErrors when building the AST
6
+
1
7
  == 0.0.5 / 2008-11-26
2
8
 
3
9
  * 2 minor enhancements
@@ -1,7 +1,7 @@
1
1
  module TireSwing
2
2
 
3
3
  # :stopdoc:
4
- VERSION = "0.0.5"
4
+ VERSION = "0.0.6"
5
5
  LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
6
6
  PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
7
7
  # :startdoc:
@@ -47,6 +47,9 @@ require "rubygems"
47
47
  gem "extlib"
48
48
  gem "attributes"
49
49
 
50
- %w(extlib/inflection extlib/string attributes treetop).each { |lib| require lib }
50
+ require "extlib/string"
51
+ require "extlib/inflection" unless "".respond_to?(:pluralize) # activesupport compatibility mode to prevent interference
52
+
53
+ %w(attributes treetop).each { |lib| require lib }
51
54
 
52
55
  TireSwing.require_all_libs_relative_to __FILE__
@@ -1,7 +1,7 @@
1
1
  module TireSwing
2
2
  class ParseError < StandardError
3
3
  attr_reader :parser
4
- def initialize(message, parser)
4
+ def initialize(message, parser=nil)
5
5
  @parser = parser
6
6
  super(message)
7
7
  end
@@ -15,12 +15,9 @@ module TireSwing
15
15
  attribs.each do |attrib|
16
16
  case attrib
17
17
  when Symbol, String
18
- attribute(attrib.to_s) { raise "no value given for #{attrib}" }
18
+ add_mapping(attrib, attrib)
19
19
  when Hash
20
- attrib.each do |name, symbol|
21
- attribute(name.to_s) { raise "no value given for #{name}" }
22
- attribute_mapping[name.to_s] = symbol
23
- end
20
+ attrib.each { |name, symbol| add_mapping(name, symbol) }
24
21
  end
25
22
  end
26
23
  end
@@ -31,6 +28,12 @@ module TireSwing
31
28
  @attribute_mapping ||= {}
32
29
  end
33
30
 
31
+ def self.add_mapping(name, value)
32
+ attribute(name.to_s) { raise "no value given for #{name}" }
33
+ attribute_mapping[name.to_s] = value
34
+ end
35
+
36
+ # keep track of where this node lives in the tree
34
37
  attr_accessor :parent
35
38
 
36
39
  # Instantiate a node.
@@ -56,13 +59,9 @@ module TireSwing
56
59
  protected
57
60
 
58
61
  # Auto-builds this node using the provided parsed node and the defined attributes and mapped attributes.
59
- def build_from_parsed_node(parsed_node)
62
+ def build_from_parsed_node(node)
60
63
  attributes.each do |attrib|
61
- if handler = mapping(attrib)
62
- value = apply_mapping(handler, parsed_node)
63
- else
64
- value = parsed_node.send(attrib)
65
- end
64
+ value = apply_mapping(attrib, node)
66
65
 
67
66
  value = if value.kind_of?(Array)
68
67
  value.map { |val| extract_value(val) }
@@ -74,18 +73,28 @@ module TireSwing
74
73
  end
75
74
  end
76
75
 
77
- def apply_mapping(handler, parsed_node)
78
- # TODO add in handler for arrays of methods to call in order
76
+ def apply_mapping(attrib, node)
77
+ handler = mapping_for(attrib)
78
+
79
79
  if handler.kind_of?(Proc)
80
- value = handler.call(parsed_node)
80
+ value = handler.call(node)
81
81
  else
82
- # TODO need to add more error checking
83
- if parsed_node.respond_to?(handler)
84
- value = parsed_node.send(handler)
85
- else
86
- value = parsed_node.text_value.send(handler)
87
- end
82
+ send_handler_method handler, node
83
+ end
84
+
85
+ end
86
+
87
+ def send_handler_method(handler, node)
88
+ if node.respond_to?(handler)
89
+ value = node.send(handler)
90
+ else
91
+ value = node.text_value.send(handler)
88
92
  end
93
+ rescue NoMethodError
94
+ context = node.text_value.split("\n")
95
+ context = context.size > 1 ? context.first + "..." : context
96
+ raise ParseError,
97
+ %Q{expected node containing "#{context}" or its text value to respond to #{handler.inspect}}
89
98
  end
90
99
 
91
100
  def extract_value(value)
@@ -104,7 +113,7 @@ module TireSwing
104
113
  self.class.attributes
105
114
  end
106
115
 
107
- def mapping(name)
116
+ def mapping_for(name)
108
117
  self.class.attribute_mapping[name]
109
118
  end
110
119
 
@@ -29,7 +29,13 @@ module TireSwing
29
29
  #
30
30
  # You can specify an alternate module which contains the AST if desired.
31
31
  def self.parses_grammar(grammar, ast=nil)
32
- parser = Extlib::Inflection.constantize(grammar.to_s + "Parser")
32
+ # use either extlib or activesupport, if that's loaded instead
33
+ parser = grammar.to_s + "Parser"
34
+ parser = if defined?(Extlib::Inflection)
35
+ Extlib::Inflection.constantize
36
+ else
37
+ parser.constantize
38
+ end
33
39
  ast ||= grammar
34
40
  parser.module_eval do
35
41
  extend ParserExtension
@@ -6,6 +6,14 @@ describe TireSwing::ParseError do
6
6
  it "takes a message and a parser instance" do
7
7
  TireSwing::ParseError.new("message", "parser").should be_an_instance_of(TireSwing::ParseError)
8
8
  end
9
+
10
+ it "does not require a parser instance" do
11
+ TireSwing::ParseError.new("message").message.should == "message"
12
+ end
13
+ end
14
+
15
+ it "is a subclass of StandardError" do
16
+ TireSwing::ParseError.new("message", "parser").should be_a_kind_of(StandardError)
9
17
  end
10
18
 
11
19
  it "has a message" do
@@ -48,11 +48,6 @@ describe TireSwing::Node do
48
48
  n = @node.new
49
49
  lambda { n.lhs }.should raise_error(RuntimeError, "no value given for lhs")
50
50
  end
51
-
52
- it "returns a class with an attribute mapping" do
53
- @node.attribute_mapping.should == {"lhs" => :left_value, "rhs" => :right_value}
54
- end
55
-
56
51
  end
57
52
 
58
53
  describe "with a mix of named attributes and hash attributes" do
@@ -63,11 +58,6 @@ describe TireSwing::Node do
63
58
  it "creates a class with attributes matching the named attributes and hash keys" do
64
59
  @node.attributes.should == %w(one two three)
65
60
  end
66
-
67
- it "updates the attribute mapping" do
68
- @node.attribute_mapping.should == {"three" => :value}
69
- end
70
-
71
61
  end
72
62
 
73
63
  end
@@ -153,6 +143,28 @@ describe TireSwing::Node do
153
143
  end
154
144
  end
155
145
 
146
+ describe "for a node lacking the required named attribute" do
147
+ it "raises a parse exception including the text value of the node" do
148
+ node = TireSwing::Node.create :foo
149
+ @top.should_receive(:foo).and_raise(NoMethodError.new("undefined method `foo'..."))
150
+ @top.stub!(:text_value).and_return("value")
151
+ lambda do
152
+ node.new(@top)
153
+ end.should raise_error(TireSwing::ParseError, /expected.*"value".*foo/)
154
+ end
155
+ end
156
+
157
+ describe "for a node lacking the defined method for a name/method mapping" do
158
+ it "raises an exception including the text value of the node" do
159
+ node = TireSwing::Node.create :foo => :bar
160
+ @top.should_receive(:bar).and_raise(NoMethodError.new("undefined method `bar'..."))
161
+ @top.stub!(:text_value).and_return("value")
162
+ lambda do
163
+ node.new(@top)
164
+ end.should raise_error(TireSwing::ParseError, /expected.*"value".*bar/)
165
+ end
166
+ end
167
+
156
168
  end
157
169
  end
158
170
 
@@ -70,7 +70,7 @@ end
70
70
 
71
71
  describe "with invalid input" do
72
72
 
73
- it "raises an exception with" do
73
+ it "raises an exception with the parsing error" do
74
74
  lambda { parse }.should raise_error(TireSwing::ParseError, /as3f.*\^/m)
75
75
  end
76
76
 
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{tire_swing}
5
- s.version = "0.0.5"
5
+ s.version = "0.0.6"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Nathan Witmer"]
9
- s.date = %q{2008-11-26}
9
+ s.date = %q{2008-12-05}
10
10
  s.description = %q{Simple node and visitor definitions for Treetop grammars.}
11
11
  s.email = %q{nwitmer at gmail dot com}
12
12
  s.extra_rdoc_files = ["History.txt", "README.txt", "spec/fixtures/assignments.txt"]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aniero-tire_swing
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathan Witmer
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-11-26 00:00:00 -08:00
12
+ date: 2008-12-05 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency