Permalink
Browse files

+ handles empty rules gracefully

  • Loading branch information...
1 parent 9b71898 commit 06a7781da6c83ae1019c32e5e3420695dec66f74 @kschiess committed Oct 29, 2010
Showing with 79 additions and 8 deletions.
  1. +15 −0 example/empty.rb
  2. +12 −1 lib/parslet/atoms.rb
  3. +23 −7 spec/unit/parslet/atoms/entity_spec.rb
  4. +29 −0 spec/unit/parslet/parslet_spec.rb
View
@@ -0,0 +1,15 @@
+# Basically just demonstrates that you can leave rules empty and get a nice
+# NotImplementedError. A way to quickly spec out your parser rules?
+
+$:.unshift '../lib'
+
+require 'parslet'
+
+class Parser
+ include Parslet
+
+ rule(:empty) { }
+end
+
+
+Parser.new.empty.parslet
View
@@ -466,7 +466,9 @@ def try(io)
end
def parslet
- @parslet ||= context.instance_eval(&block)
+ @parslet ||= context.instance_eval(&block).tap { |p|
+ raise_not_implemented unless p
+ }
end
def to_s_inner(prec)
@@ -476,6 +478,15 @@ def to_s_inner(prec)
def error_tree
parslet.error_tree
end
+
+ private
+ def raise_not_implemented
+ trace = caller.reject {|l| l =~ %r{#{Regexp.escape(__FILE__)}}} # blatantly stolen from dependencies.rb in activesupport
+ exception = NotImplementedError.new("rule(#{name.inspect}) { ... } returns nil. Still not implemented, but already used?")
+ exception.set_backtrace(trace)
+
+ raise exception
+ end
end
end
@@ -1,15 +1,31 @@
require 'spec_helper'
describe Parslet::Atoms::Entity do
- let(:named) { Parslet::Atoms::Entity.new('name', self, proc { Parslet.str('bar') }) }
+ context "when constructed with str('bar') inside" do
+ let(:named) { Parslet::Atoms::Entity.new('name', self, proc { Parslet.str('bar') }) }
- it "should parse 'bar' without raising exceptions" do
- named.parse('bar')
- end
+ it "should parse 'bar' without raising exceptions" do
+ named.parse('bar')
+ end
+ it "should raise when applied to 'foo'" do
+ lambda {
+ named.parse('foo')
+ }.should raise_error(Parslet::ParseFailed)
+ end
- describe "#inspect" do
- it "should return the name of the entity" do
- named.inspect.should == 'NAME'
+ describe "#inspect" do
+ it "should return the name of the entity" do
+ named.inspect.should == 'NAME'
+ end
+ end
+ end
+ context "when constructed with empty block" do
+ let(:entity) { Parslet::Atoms::Entity.new('name', self, proc { }) }
+
+ it "should raise NotImplementedError" do
+ lambda {
+ entity.parse('some_string')
+ }.should raise_error(NotImplementedError)
end
end
@@ -0,0 +1,29 @@
+require 'spec_helper'
+
+describe Parslet do
+ include Parslet
+
+ describe "<- .rule" do
+ # Rules define methods. This can be easily tested by defining them right
+ # here.
+ context "empty rule" do
+ rule(:empty) { }
+
+ it "should raise a NotImplementedError" do
+ lambda {
+ empty.parslet
+ }.should raise_error(NotImplementedError)
+ end
+ end
+
+ context "containing 'any'" do
+ rule(:any_rule) { any }
+ subject { any_rule }
+
+ it { should be_a Parslet::Atoms::Entity }
+ it "should memoize the returned instance" do
+ any_rule.object_id.should == any_rule.object_id
+ end
+ end
+ end
+end

0 comments on commit 06a7781

Please sign in to comment.