[DRE-commits] [ruby-parslet] 04/05: Import patches from upstream

Youhei SASAKI uwabami-guest at moszumanska.debian.org
Sun Jan 26 01:36:29 UTC 2014


This is an automated email from the git hooks/post-receive script.

uwabami-guest pushed a commit to branch master
in repository ruby-parslet.

commit cd25278beb2bc60ffd89fccb2ad17db5f48e37cd
Author: Youhei SASAKI <uwabami at gfd-dennou.org>
Date:   Sun Jan 26 10:35:31 2014 +0900

    Import patches from upstream
    
    Signed-off-by: Youhei SASAKI <uwabami at gfd-dennou.org>
---
 Rakefile                                           |    1 +
 ...port-rspec-gemspec-from-upstream-Git-repo.patch | 2855 ++++++++++++++++++++
 debian/patches/series                              |    2 +-
 example/json.rb                                    |    1 +
 4 files changed, 2858 insertions(+), 1 deletion(-)

diff --git a/Rakefile b/Rakefile
index 749e476..cf39b82 100644
--- a/Rakefile
+++ b/Rakefile
@@ -2,6 +2,7 @@ require 'rdoc/task'
 require 'sdoc'
 
 require 'rspec/core/rake_task'
+require "rubygems/package_task"
 
 desc "Run all tests: Exhaustive."
 RSpec::Core::RakeTask.new
diff --git a/debian/patches/0001-Import-rspec-gemspec-from-upstream-Git-repo.patch b/debian/patches/0001-Import-rspec-gemspec-from-upstream-Git-repo.patch
new file mode 100644
index 0000000..5d0129d
--- /dev/null
+++ b/debian/patches/0001-Import-rspec-gemspec-from-upstream-Git-repo.patch
@@ -0,0 +1,2855 @@
+From: Youhei SASAKI <uwabami at gfd-dennou.org>
+Date: Tue, 14 Jan 2014 15:39:51 +0900
+Subject: Import rspec, gemspec from upstream Git repo.
+
+Signed-off-by: Youhei SASAKI <uwabami at gfd-dennou.org>
+---
+ parslet.gemspec                              |  18 ++
+ spec/acceptance/examples_spec.rb             |  37 +++
+ spec/acceptance/infix_parser_spec.rb         | 112 +++++++
+ spec/acceptance/regression_spec.rb           | 314 ++++++++++++++++++++
+ spec/acceptance/repetition_and_maybe_spec.rb |  42 +++
+ spec/acceptance/unconsumed_input_spec.rb     |  21 ++
+ spec/parslet/atom_results_spec.rb            |  39 +++
+ spec/parslet/atoms/alternative_spec.rb       |  26 ++
+ spec/parslet/atoms/base_spec.rb              | 124 ++++++++
+ spec/parslet/atoms/capture_spec.rb           |  21 ++
+ spec/parslet/atoms/combinations_spec.rb      |   5 +
+ spec/parslet/atoms/dsl_spec.rb               |  17 ++
+ spec/parslet/atoms/entity_spec.rb            |  52 ++++
+ spec/parslet/atoms/infix_spec.rb             |   5 +
+ spec/parslet/atoms/lookahead_spec.rb         |  22 ++
+ spec/parslet/atoms/named_spec.rb             |   4 +
+ spec/parslet/atoms/re_spec.rb                |  14 +
+ spec/parslet/atoms/repetition_spec.rb        |  24 ++
+ spec/parslet/atoms/scope_spec.rb             |  26 ++
+ spec/parslet/atoms/sequence_spec.rb          |  28 ++
+ spec/parslet/atoms/str_spec.rb               |  15 +
+ spec/parslet/atoms/visitor_spec.rb           |  80 +++++
+ spec/parslet/atoms_spec.rb                   | 429 +++++++++++++++++++++++++++
+ spec/parslet/convenience_spec.rb             |  48 +++
+ spec/parslet/error_reporter/deepest_spec.rb  |  73 +++++
+ spec/parslet/error_reporter/tree_spec.rb     |   7 +
+ spec/parslet/export_spec.rb                  |  67 +++++
+ spec/parslet/expression/treetop_spec.rb      |  74 +++++
+ spec/parslet/minilisp.citrus                 |  29 ++
+ spec/parslet/minilisp.tt                     |  29 ++
+ spec/parslet/parser_spec.rb                  |  31 ++
+ spec/parslet/parslet_spec.rb                 |  38 +++
+ spec/parslet/pattern_spec.rb                 | 268 +++++++++++++++++
+ spec/parslet/rig/rspec_spec.rb               |  35 +++
+ spec/parslet/scope_spec.rb                   |  45 +++
+ spec/parslet/slice_spec.rb                   | 134 +++++++++
+ spec/parslet/source/line_cache_spec.rb       |  74 +++++
+ spec/parslet/source_spec.rb                  | 165 +++++++++++
+ spec/parslet/transform/context_spec.rb       |  35 +++
+ spec/parslet/transform_spec.rb               | 144 +++++++++
+ spec/spec_helper.rb                          |  24 ++
+ 41 files changed, 2795 insertions(+)
+ create mode 100644 parslet.gemspec
+ create mode 100644 spec/acceptance/examples_spec.rb
+ create mode 100644 spec/acceptance/infix_parser_spec.rb
+ create mode 100644 spec/acceptance/regression_spec.rb
+ create mode 100644 spec/acceptance/repetition_and_maybe_spec.rb
+ create mode 100644 spec/acceptance/unconsumed_input_spec.rb
+ create mode 100644 spec/parslet/atom_results_spec.rb
+ create mode 100644 spec/parslet/atoms/alternative_spec.rb
+ create mode 100644 spec/parslet/atoms/base_spec.rb
+ create mode 100644 spec/parslet/atoms/capture_spec.rb
+ create mode 100644 spec/parslet/atoms/combinations_spec.rb
+ create mode 100644 spec/parslet/atoms/dsl_spec.rb
+ create mode 100644 spec/parslet/atoms/entity_spec.rb
+ create mode 100644 spec/parslet/atoms/infix_spec.rb
+ create mode 100644 spec/parslet/atoms/lookahead_spec.rb
+ create mode 100644 spec/parslet/atoms/named_spec.rb
+ create mode 100644 spec/parslet/atoms/re_spec.rb
+ create mode 100644 spec/parslet/atoms/repetition_spec.rb
+ create mode 100644 spec/parslet/atoms/scope_spec.rb
+ create mode 100644 spec/parslet/atoms/sequence_spec.rb
+ create mode 100644 spec/parslet/atoms/str_spec.rb
+ create mode 100644 spec/parslet/atoms/visitor_spec.rb
+ create mode 100644 spec/parslet/atoms_spec.rb
+ create mode 100644 spec/parslet/convenience_spec.rb
+ create mode 100644 spec/parslet/error_reporter/deepest_spec.rb
+ create mode 100644 spec/parslet/error_reporter/tree_spec.rb
+ create mode 100644 spec/parslet/export_spec.rb
+ create mode 100644 spec/parslet/expression/treetop_spec.rb
+ create mode 100644 spec/parslet/minilisp.citrus
+ create mode 100644 spec/parslet/minilisp.tt
+ create mode 100644 spec/parslet/parser_spec.rb
+ create mode 100644 spec/parslet/parslet_spec.rb
+ create mode 100644 spec/parslet/pattern_spec.rb
+ create mode 100644 spec/parslet/rig/rspec_spec.rb
+ create mode 100644 spec/parslet/scope_spec.rb
+ create mode 100644 spec/parslet/slice_spec.rb
+ create mode 100644 spec/parslet/source/line_cache_spec.rb
+ create mode 100644 spec/parslet/source_spec.rb
+ create mode 100644 spec/parslet/transform/context_spec.rb
+ create mode 100644 spec/parslet/transform_spec.rb
+ create mode 100644 spec/spec_helper.rb
+
+--- /dev/null
++++ ruby-parslet/parslet.gemspec
+@@ -0,0 +1,18 @@
++# -*- encoding: utf-8 -*-
++
++Gem::Specification.new do |s|
++  s.name = 'parslet'
++  s.version = '1.5.0'
++
++  s.authors = ['Kaspar Schiess']
++  s.email = 'kaspar.schiess at absurd.li'
++  s.extra_rdoc_files = ['README']
++  s.files = %w(HISTORY.txt LICENSE Rakefile README) + Dir.glob("{lib,example}/**/*")
++  s.homepage = 'http://kschiess.github.com/parslet'
++  s.license = 'MIT'
++  s.rdoc_options = ['--main', 'README']
++  s.require_paths = ['lib']
++  s.summary = 'Parser construction library with great error reporting in Ruby.'  
++  
++  s.add_dependency 'blankslate', '~> 2.0'
++end
+--- /dev/null
++++ ruby-parslet/spec/acceptance/examples_spec.rb
+@@ -0,0 +1,37 @@
++require 'spec_helper'
++require 'open3'
++
++describe "Regression on" do
++  Dir["example/*.rb"].each do |example|
++    context example do
++      # Generates a product path for a given example file. 
++      def product_path(str, ext)
++        str.
++          gsub('.rb', ".#{ext}").
++          gsub('example/','example/output/')
++      end
++      
++      it "runs successfully", :ruby => 1.9 do
++        stdin, stdout, stderr = Open3.popen3("ruby #{example}")
++        
++        handle_map = {
++          stdout => :out, 
++          stderr => :err
++        }
++        expectation_found = handle_map.any? do |io, ext|
++          name = product_path(example, ext)
++          
++          if File.exists?(name)
++            io.read.strip.should == File.read(name).strip
++            true
++          end
++        end
++        
++        unless expectation_found
++          fail "Example doesn't have either an .err or an .out file. "+
++            "Please create in examples/output!"
++        end
++      end
++    end
++  end
++end
+--- /dev/null
++++ ruby-parslet/spec/acceptance/regression_spec.rb
+@@ -0,0 +1,314 @@
++# Encoding: UTF-8
++
++require 'spec_helper'
++
++require 'parslet'
++
++describe "Regressions from real examples" do
++  # This parser piece produces on the left a subtree that is keyed (a hash)
++  # and on the right a subtree that is a repetition of such subtrees. I've
++  # for now decided that these would merge into the repetition such that the
++  # return value is an array. This avoids maybe loosing keys/values in a 
++  # hash merge. 
++  #
++  class ArgumentListParser
++    include Parslet
++
++    rule :argument_list do
++      expression.as(:argument) >> 
++        (comma >> expression.as(:argument)).repeat
++    end
++    rule :expression do
++      string
++    end
++    rule :string do
++      str('"') >> 
++      (
++        str('\\') >> any |
++        str('"').absent? >> any
++      ).repeat.as(:string) >>
++      str('"') >> space?
++    end
++    rule :comma do
++      str(',') >> space?
++    end
++    rule :space? do
++      space.maybe
++    end
++    rule :space do
++      match("[ \t]").repeat(1)
++    end
++    
++    def parse(str)
++      argument_list.parse(str)
++    end
++  end
++  describe ArgumentListParser do
++    let(:instance) { ArgumentListParser.new }
++    it "should have method expression" do
++      instance.should respond_to(:expression)
++    end 
++    it 'should parse "arg1", "arg2"' do
++      result = ArgumentListParser.new.parse('"arg1", "arg2"')
++      
++      result.should have(2).elements
++      result.each do |r|
++        r[:argument]
++      end
++    end
++    it 'should parse "arg1", "arg2", "arg3"' do
++      result = ArgumentListParser.new.parse('"arg1", "arg2", "arg3"')
++      
++      result.should have(3).elements
++      result.each do |r|
++        r[:argument]
++      end
++    end
++  end
++
++  class ParensParser < Parslet::Parser
++    rule(:balanced) {
++      str('(').as(:l) >> balanced.maybe.as(:m) >> str(')').as(:r)
++    }
++  
++    root(:balanced)
++  end
++  describe ParensParser do
++    let(:instance) { ParensParser.new }
++    
++    context "statefulness: trying several expressions in sequence" do
++      it "should not be stateful" do
++        # NOTE: Since you've come here to read this, I'll explain why
++        # this is broken and not fixed: You're looking at the tuning branch, 
++        # which rewrites a bunch of stuff - so I have failing tests to 
++        # remind me of what is left to be done. And to remind you not to 
++        # trust this code. 
++        instance.parse('(())')
++        lambda {
++          instance.parse('((()))')
++          instance.parse('(((())))')
++        }.should_not raise_error(Parslet::ParseFailed)
++      end 
++    end
++    context "expression '(())'" do
++      let(:result) { instance.parse('(())') }
++
++      it "should yield a doubly nested hash" do
++        result.should be_a(Hash)
++        result.should have_key(:m)
++        result[:m].should be_a(Hash)   # This was an array earlier
++      end 
++      context "inner hash" do
++        let(:inner) { result[:m] }
++        
++        it "should have nil as :m" do
++          inner[:m].should be_nil
++        end 
++      end
++    end
++  end
++
++  class ALanguage < Parslet::Parser
++    root(:expressions)
++
++    rule(:expressions) { (line >> eol).repeat(1) | line }
++    rule(:line) { space? >> an_expression.as(:exp).repeat }
++    rule(:an_expression) { str('a').as(:a) >> space? }
++
++    rule(:eol) { space? >> match["\n\r"].repeat(1) >> space? }
++
++    rule(:space?) { space.repeat }
++    rule(:space) { multiline_comment.as(:multi) | line_comment.as(:line) | str(' ') }
++
++    rule(:line_comment) { str('//') >> (match["\n\r"].absent? >> any).repeat }
++    rule(:multiline_comment) { str('/*') >> (str('*/').absent? >> any).repeat >> str('*/') }
++  end
++  describe ALanguage do
++    def remove_indent(s)
++      s.to_s.lines.map { |l| l.chomp.strip }.join("\n")
++    end
++    
++    it "should count lines correctly" do
++      cause = catch_failed_parse {
++        subject.parse('a
++          a a a 
++          aaa // ff
++          /* 
++          a
++          */
++          b
++        ')
++      }
++
++      remove_indent(cause.ascii_tree).should == remove_indent(%q(
++      Expected one of [(LINE EOL){1, }, LINE] at line 1 char 1.
++      |- Extra input after last repetition at line 7 char 11.
++      |  `- Failed to match sequence (LINE EOL) at line 7 char 11.
++      |     `- Failed to match sequence (SPACE? [\n\r]{1, } SPACE?) at line 7 char 11.
++      |        `- Expected at least 1 of [\n\r] at line 7 char 11.
++      |           `- Failed to match [\n\r] at line 7 char 11.
++      `- Don't know what to do with "\n         " at line 1 char 2.).strip)
++    end 
++  end
++
++  class BLanguage < Parslet::Parser
++    root :expression
++    rule(:expression) { b.as(:one) >> b.as(:two) }
++    rule(:b) { str('b') }
++  end
++  describe BLanguage do
++    it "should parse 'bb'" do
++      subject.should parse('bb').as(:one => 'b', :two => 'b')
++    end 
++    it "should transform with binding constraint" do
++      transform = Parslet::Transform.new do |t|
++        t.rule(:one => simple(:b), :two => simple(:b)) { :ok }
++      end
++      transform.apply(subject.parse('bb')).should == :ok
++    end 
++  end
++
++  class UnicodeLanguage < Parslet::Parser
++    root :gobble
++    rule(:gobble) { any.repeat }
++  end
++  describe UnicodeLanguage do
++    it "should parse UTF-8 strings" do
++      subject.should parse('éèäöü').as('éèäöü')
++      subject.should parse('RubyKaigi2009のテーマは、「変わる/変える」です。 前回の').as('RubyKaigi2009のテーマは、「変わる/変える」です。 前回の')
++    end 
++  end
++  
++  class UnicodeSentenceLanguage < Parslet::Parser
++    rule(:sentence) { (match('[^。]').repeat(1) >> str("。")).as(:sentence) }
++    rule(:sentences) { sentence.repeat }
++    root(:sentences)
++  end
++  describe UnicodeSentenceLanguage, :ruby => 1.9 do
++    let(:string) {
++      "RubyKaigi2009のテーマは、「変わる/変える」です。 前回の" +
++      "RubyKaigi2008のテーマであった「多様性」の言葉の通り、 " +
++      "2008年はRubyそのものに関しても、またRubyの活躍する舞台に関しても、 " +
++      "ますます多様化が進みつつあります。RubyKaigi2008は、そのような " +
++      "Rubyの生態系をあらためて認識する場となりました。 しかし、" +
++      "こうした多様化が進む中、異なる者同士が単純に距離を 置いたままでは、" +
++      "その違いを認識したところであまり意味がありません。 異なる実装、" +
++      "異なる思想、異なる背景といった、様々な多様性を理解しつつ、 " +
++      "すり合わせるべきものをすり合わせ、変えていくべきところを " +
++      "変えていくことが、豊かな未来へとつながる道に違いありません。"
++    }
++    
++    it "should parse sentences" do
++      subject.should parse(string)
++    end 
++  end
++
++  class TwoCharLanguage < Parslet::Parser
++    root :twochar
++    rule(:twochar) { any >> str('2') }
++  end
++  describe TwoCharLanguage do
++    def di(s)
++      s.strip.to_s.lines.map { |l| l.chomp.strip }.join("\n")
++    end
++
++    it "should raise an error" do
++      error = catch_failed_parse {
++        subject.parse('123') }
++      di(error.ascii_tree).should == di(%q(
++        Failed to match sequence (. '2') at line 1 char 2.
++        `- Don't know what to do with "3" at line 1 char 3.
++      ))
++    end 
++  end
++
++  # Issue #68: Extra input reporting, written by jmettraux
++  class RepetitionParser < Parslet::Parser
++    rule(:nl)      { match('[\s]').repeat(1) }
++    rule(:nl?)     { nl.maybe }
++    rule(:sp)      { str(' ').repeat(1) }
++    rule(:sp?)     { str(' ').repeat(0) }
++    rule(:line)    { sp >> str('line') }
++    rule(:body)    { ((line | block) >> nl).repeat(0) }
++    rule(:block)   { sp? >> str('begin') >> sp >> match('[a-z]') >> nl >>
++                     body >> sp? >> str('end') }
++    rule(:blocks)  { nl? >> block >> (nl >> block).repeat(0) >> nl? }
++
++    root(:blocks)
++  end
++  describe RepetitionParser do
++    def di(s)
++      s.strip.to_s.lines.map { |l| l.chomp.strip }.join("\n")
++    end
++
++    it 'parses a block' do
++      subject.parse(%q{
++        begin a
++        end
++      })
++    end
++    it 'parses nested blocks' do
++      subject.parse(%q{
++        begin a
++          begin b
++          end
++        end
++      })
++    end
++    it 'parses successive blocks' do
++      subject.parse(%q{
++        begin a
++        end
++        begin b
++        end
++      })
++    end
++    it 'fails gracefully on a missing end' do
++      error = catch_failed_parse {
++        subject.parse(%q{
++          begin a
++            begin b
++          end
++        }) }
++      
++      di(error.ascii_tree).should == di(%q(
++        Failed to match sequence (NL? BLOCK (NL BLOCK){0, } NL?) at line 2 char 11.
++        `- Failed to match sequence (SP? 'begin' SP [a-z] NL BODY SP? 'end') at line 5 char 9.
++           `- Premature end of input at line 5 char 9.
++        ))
++    end
++    it 'fails gracefully on a missing end (2)' do
++      error = catch_failed_parse {
++        subject.parse(%q{
++          begin a
++          end
++          begin b
++            begin c
++          end
++        }) }
++
++      di(error.ascii_tree).should == di(%q(
++        Failed to match sequence (NL? BLOCK (NL BLOCK){0, } NL?) at line 3 char 14.
++        `- Don't know what to do with "begin b\n  " at line 4 char 11.
++        ))
++    end
++    it 'fails gracefully on a missing end (deepest reporter)' do
++      error = catch_failed_parse {
++        subject.parse(%q{
++            begin a
++            end
++            begin b
++              begin c
++                li
++              end
++            end
++          },
++          :reporter => Parslet::ErrorReporter::Deepest.new) }
++
++      di(error.ascii_tree).should == di(%q(
++        Failed to match sequence (NL? BLOCK (NL BLOCK){0, } NL?) at line 3 char 16.
++        `- Expected "end", but got "li\n" at line 6 char 17.
++        ))
++    end
++  end
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/acceptance/repetition_and_maybe_spec.rb
+@@ -0,0 +1,42 @@
++require 'spec_helper'
++
++describe "Tree output" do
++  extend Parslet
++
++  def self.hash_examples(h)
++    h.each do |atom, expected|
++      it "should convert #{atom} to #{expected.inspect}" do
++        atom.parse(input).should == expected
++      end
++    end
++  end
++
++  context "when parsing the empty string" do
++    let(:input) { '' }
++    hash_examples( 
++      # No naming 
++      str('a').maybe              => '', 
++      str('a').repeat             => '',
++      
++      # Named contents: maybe yields nil
++      str('a').maybe.as(:f)       => {:f => nil},
++      str('a').repeat.as(:f)      => {:f => []}, 
++      
++      # Contents that aren't simple strings
++      (str('a') >> str('b')).maybe.as(:f)     => {:f => nil},
++      (str('a') >> str('b')).repeat.as(:f)    => {:f => []}, 
++      
++      # The other way around: Contents would be tagged, but nil result isn't
++      (str('a') >> str('b')).as(:f).maybe     => '',
++      (str('a') >> str('b')).as(:f).repeat    => ''
++    )
++  end
++  
++  context "when parsing 'aa'" do
++    let(:input) { 'aa' }
++    hash_examples(
++      # since they're not named, repetitions get merged together.
++      str('a').as(:a).repeat >> str('a').as(:a).repeat => [{:a=>'a'},{:a=>'a'}]
++    )
++  end
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/acceptance/unconsumed_input_spec.rb
+@@ -0,0 +1,21 @@
++require 'spec_helper'
++
++describe "Unconsumed input:" do
++  class RepeatingBlockParser < Parslet::Parser
++    root :expressions
++    rule(:expressions) { expression.repeat }
++    rule(:expression) { str('(') >> aab >> str(')') }
++    rule(:aab) { str('a').repeat(1) >> str('b') }
++  end
++  describe RepeatingBlockParser do
++    let(:parser) { described_class.new }
++    it "throws annotated error" do
++      error = catch_failed_parse { parser.parse('(aaac)') }
++    end
++    it "doesn't error out if prefix is true" do
++      expect {
++        parser.parse('(aaac)', :prefix => true)
++      }.not_to raise_error
++    end
++  end
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/parslet/atom_results_spec.rb
+@@ -0,0 +1,39 @@
++require 'spec_helper'
++
++describe 'Result of a Parslet#parse' do
++  include Parslet; extend Parslet
++  
++  describe "regression" do
++    [
++      # Behaviour with maybe-nil
++      [str('foo').maybe >> str('bar'), "bar", "bar"],
++      [str('bar') >> str('foo').maybe, "bar", 'bar'], 
++      
++      # These might be hard to understand; look at the result of 
++      #   str.maybe >> str
++      # and 
++      #   str.maybe >> str first. 
++      [(str('f').maybe >> str('b')).repeat, "bb", "bb"],
++      [(str('b') >> str('f').maybe).repeat, "bb", 'bb'], 
++      
++      [str('a').as(:a) >> (str('b') >> str('c').as(:a)).repeat, 'abc', 
++        [{:a=>'a'}, {:a=>'c'}]], 
++      
++      [str('a').as(:a).repeat >> str('b').as(:b).repeat, 'ab', [{:a=>'a'}, {:b=>'b'}]], 
++      
++      # Repetition behaviour / named vs. unnamed
++      [str('f').repeat, '', ''], 
++      [str('f').repeat.as(:f), '', {:f => []}],
++
++      # Maybe behaviour / named vs. unnamed
++      [str('f').maybe, '', ''], 
++      [str('f').maybe.as(:f), '', {:f => nil}],
++    ].each do |parslet, input, result|
++      context "#{parslet.inspect}" do
++        it "should parse \"#{input}\" into \"#{result}\"" do
++          parslet.parse(input).should == result
++        end
++      end
++    end
++  end
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/parslet/atoms/alternative_spec.rb
+@@ -0,0 +1,26 @@
++require 'spec_helper'
++
++describe Parslet::Atoms::Alternative do
++  include Parslet
++  
++  describe '| shortcut' do
++    let(:alternative) { str('a') | str('b') }
++    
++    context "when chained with different atoms" do
++      before(:each) { 
++        # Chain something else to the alternative parslet. If it modifies the
++        # parslet atom in place, we'll notice: 
++        
++        alternative | str('d')
++      }
++      let!(:chained) { alternative | str('c') }
++      
++      
++      it "is side-effect free" do
++        chained.should parse('c')
++        chained.should parse('a')
++        chained.should_not parse('d')
++      end 
++    end
++  end
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/parslet/atoms/base_spec.rb
+@@ -0,0 +1,124 @@
++require 'spec_helper'
++
++describe Parslet::Atoms::Base do
++  let(:parslet) { Parslet::Atoms::Base.new }
++  let(:context) { Parslet::Atoms::Context.new }
++
++  describe "<- #try(io)" do
++    it "should raise NotImplementedError" do
++      lambda {
++        parslet.try(flexmock(:io), context, false)
++      }.should raise_error(NotImplementedError)
++    end 
++  end
++  describe "<- #flatten_sequence" do
++    [
++      # 9 possibilities for making a word of 2 letters from the alphabeth of
++      # A(rray), H(ash) and S(tring). Make sure that all results are valid.
++      #
++      ['a', 'b'], 'ab',                             # S S
++      [['a'], ['b']], ['a', 'b'],                   # A A
++      [{:a=>'a'}, {:b=>'b'}], {:a=>'a',:b=>'b'},    # H H
++      
++      [{:a=>'a'}, ['a']], [{:a=>'a'}, 'a'],         # H A
++      [{:a=>'a'}, 's'],   {:a=>'a'},                # H S
++
++      [['a'], {:a=>'a'}], ['a', {:a=>'a'}],         # A H (symmetric to H A)
++      [['a'], 'b'], ['a'],                          # A S 
++
++      ['a', {:b=>'b'}], {:b=>'b'},                  # S H (symmetric to H S)
++      ['a', ['b']], ['b'],                          # S A (symmetric to A S)
++      
++      [nil, ['a']], ['a'],                          # handling of lhs nil
++      [nil, {:a=>'a'}], {:a=>'a'},
++      [['a'], nil], ['a'],                          # handling of rhs nil
++      [{:a=>'a'}, nil], {:a=>'a'}
++    ].each_slice(2) do |sequence, result|
++      context "for " + sequence.inspect do
++        it "should equal #{result.inspect}" do
++          parslet.flatten_sequence(sequence).should == result
++        end
++      end
++    end
++  end
++  describe "<- #flatten_repetition" do
++    def unnamed(obj)
++      parslet.flatten_repetition(obj, false)
++    end
++    
++    it "should give subtrees precedence" do
++      unnamed([[{:a=>"a"}, {:m=>"m"}], {:a=>"a"}]).should == [{:a=>"a"}]
++    end 
++  end
++  describe '#parse(source)' do
++    context "when given something that looks like a source" do
++      let(:source) { flexmock("source lookalike", 
++        :line_and_column => [1,2], 
++        :pos => 1, 
++        :chars_left => 0) }
++      
++      it "should not rewrap in a source" do
++        flexmock(Parslet::Source).
++          should_receive(:new => :source_created).never
++        
++        begin
++          parslet.parse(source) 
++        rescue NotImplementedError
++        end
++      end 
++    end
++  end
++  
++  context "when the parse fails, the exception" do
++    it "should contain a string" do
++      begin
++        Parslet.str('foo').parse('bar')
++      rescue Parslet::ParseFailed => ex
++        ex.message.should be_kind_of(String)
++      end
++    end 
++  end
++  context "when not all input is consumed" do
++    let(:parslet) { Parslet.str('foo') }
++    
++    it "should raise with a proper error message" do
++      error = catch_failed_parse {
++        parslet.parse('foobar') }
++      
++      error.to_s.should == "Don't know what to do with \"bar\" at line 1 char 4."
++    end 
++  end
++  context "when only parsing string prefix" do
++    let(:parslet) { Parslet.str('foo') >> Parslet.str('bar') }
++    
++    it "returns the first half on a prefix parse" do
++      parslet.parse('foobarbaz', :prefix => true).should == 'foobar'
++    end 
++  end
++
++  describe ':reporter option' do
++    let(:parslet) { Parslet.str('test') >> Parslet.str('ing') }
++    let(:reporter) { flexmock(:reporter) }
++    
++    it "replaces the default reporter" do
++      cause = flexmock(:cause)
++      
++      # Two levels of the parse, calling two different error reporting
++      # methods.
++      reporter.
++        should_receive(:err_at).once
++      reporter.
++        should_receive(:err => cause).once
++      
++      # The final cause will be sent the #raise method.
++      cause.
++        should_receive(:raise).once.and_throw(:raise)
++      
++      catch(:raise) {
++        parslet.parse('testung', :reporter => reporter)
++        
++        fail "NEVER REACHED"
++      }
++    end 
++  end
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/parslet/atoms/capture_spec.rb
+@@ -0,0 +1,21 @@
++require 'spec_helper'
++
++describe Parslet::Atoms::Capture do
++  include Parslet
++  
++  let(:context) { Parslet::Atoms::Context.new(nil) }
++  
++  def inject string, parser
++    source = Parslet::Source.new(string)
++    parser.apply(source, context, true)
++  end
++  
++  it "should capture simple results" do
++    inject 'a', str('a').capture(:a)
++    context.captures[:a].should == 'a'
++  end 
++  it "should capture complex results" do
++    inject 'a', str('a').as(:b).capture(:a)
++    context.captures[:a].should == {:b => 'a'}
++  end 
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/parslet/atoms/combinations_spec.rb
+@@ -0,0 +1,17 @@
++require 'spec_helper'
++
++describe "Parslet combinations" do
++  include Parslet
++
++  describe "repeat" do
++    let(:parslet) { str('a') }
++    
++    describe "(min, max)" do
++      subject { parslet.repeat(1,2) }
++      
++      it { should_not parse("") }
++      it { should parse("a") }
++      it { should parse("aa") }
++    end
++  end
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/parslet/atoms/dsl_spec.rb
+@@ -0,0 +1,17 @@
++require 'spec_helper'
++
++describe Parslet::Atoms::DSL do
++  describe "deprecated methods" do
++    let(:parslet) { Parslet.str('foo') }
++    describe "<- #absnt?" do
++      subject { parslet.absnt? }
++      its(:bound_parslet) { should == parslet }
++      its(:positive) { should == false }
++    end
++    describe "<- #prsnt?" do
++      subject { parslet.prsnt? }
++      its(:bound_parslet) { should == parslet }
++      its(:positive) { should == true }
++    end
++  end
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/parslet/atoms/entity_spec.rb
+@@ -0,0 +1,52 @@
++require 'spec_helper'
++
++describe Parslet::Atoms::Entity do
++  context "when constructed with str('bar') inside" do
++    let(:named) { Parslet::Atoms::Entity.new('name', &proc { Parslet.str('bar') }) }
++
++    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'
++      end 
++    end
++  end
++  context "when constructed with empty block" do
++    let(:entity) { Parslet::Atoms::Entity.new('name', &proc { }) }
++    
++    it "should raise NotImplementedError" do
++      lambda {
++        entity.parse('some_string')
++      }.should raise_error(NotImplementedError)
++    end 
++  end
++  
++  context "recursive definition parser" do
++    class RecDefParser
++      include Parslet
++      rule :recdef do
++        str('(') >> atom >> str(')')
++      end
++      rule :atom do
++        str('a') | str('b') | recdef
++      end
++    end
++    let(:parser) { RecDefParser.new }
++    
++    it "should parse balanced parens" do
++      parser.recdef.parse("(((a)))")
++    end
++    it "should not throw 'stack level too deep' when printing errors" do
++      cause = catch_failed_parse { parser.recdef.parse('(((a))') }
++      cause.ascii_tree
++    end
++  end
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/parslet/atoms/lookahead_spec.rb
+@@ -0,0 +1,22 @@
++require 'spec_helper'
++
++describe Parslet::Atoms::Lookahead do
++  include Parslet
++  
++  describe 'negative lookahead' do
++    it "influences the error tree" do
++      parser = str('f').absent? >> str('b')
++      cause = catch_failed_parse { parser.parse('f') }
++      
++      cause.ascii_tree.should == "Failed to match sequence (!'f' 'b') at line 1 char 1.\n`- Input should not start with 'f' at line 1 char 1.\n"
++    end 
++  end
++  describe 'positive lookahead' do
++    it "influences the error tree" do
++      parser = str('f').present? >> str('b')
++      cause = catch_failed_parse { parser.parse('b') }
++      
++      cause.ascii_tree.should == "Failed to match sequence (&'f' 'b') at line 1 char 1.\n`- Input should start with 'f' at line 1 char 1.\n"
++    end 
++  end
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/parslet/atoms/named_spec.rb
+@@ -0,0 +1,4 @@
++require 'spec_helper'
++
++describe Parslet::Atoms::Named do
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/parslet/atoms/re_spec.rb
+@@ -0,0 +1,14 @@
++require 'spec_helper'
++
++describe Parslet::Atoms::Re do
++  describe "construction" do
++    include Parslet
++    
++    it "should allow match(str) form" do
++      match('[a]').should be_a(Parslet::Atoms::Re)
++    end 
++    it "should allow match[str] form" do
++      match['a'].should be_a(Parslet::Atoms::Re)
++    end 
++  end
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/parslet/atoms/scope_spec.rb
+@@ -0,0 +1,26 @@
++require 'spec_helper'
++
++describe Parslet::Atoms::Scope do
++  include Parslet
++  include Parslet::Atoms::DSL
++  
++  
++  let(:context) { Parslet::Atoms::Context.new(nil) }
++  let(:captures) { context.captures }
++  
++  def inject string, parser
++    source = Parslet::Source.new(string)
++    parser.apply(source, context, true)
++  end
++  
++  let(:aabb) { 
++    scope {
++      match['ab'].capture(:f) >> dynamic { |s,c| str(c.captures[:f]) }
++    }
++  }
++  it "keeps values of captures outside" do
++    captures[:f] = 'old_value'
++    inject 'aa', aabb
++    captures[:f].should == 'old_value'
++  end 
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/parslet/atoms/sequence_spec.rb
+@@ -0,0 +1,28 @@
++require 'spec_helper'
++
++describe Parslet::Atoms::Sequence do
++  include Parslet
++  
++  let(:sequence) { described_class.new }
++  
++  describe '>> shortcut' do
++    let(:sequence) { str('a') >> str('b') }
++    
++    context "when chained with different atoms" do
++      before(:each) { 
++        # Chain something else to the sequence parslet. If it modifies the
++        # parslet atom in place, we'll notice: 
++        
++        sequence >> str('d')
++      }
++      let!(:chained) { sequence >> str('c') }
++      
++      
++      it "is side-effect free" do
++        chained.should parse('abc')
++        chained.should_not parse('abdc')
++      end 
++    end
++    
++  end
++end
+--- /dev/null
++++ ruby-parslet/spec/parslet/atoms/str_spec.rb
+@@ -0,0 +1,15 @@
++# Encoding: UTF-8
++
++require 'spec_helper'
++
++describe Parslet::Atoms::Str do
++  def str(s)
++    described_class.new(s)
++  end
++  
++  describe 'regression #1: multibyte characters' do
++    it "parses successfully (length check works)" do
++      str('あああ').should parse('あああ')
++    end 
++  end
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/parslet/atoms/visitor_spec.rb
+@@ -0,0 +1,80 @@
++require 'spec_helper'
++
++describe Parslet::Atoms do
++  include Parslet
++  let(:visitor) { flexmock(:visitor) }
++  
++  describe Parslet::Atoms::Str do
++    let(:parslet) { str('foo') }
++    it "should call back visitor" do
++      visitor.should_receive(:visit_str).with('foo').once
++      
++      parslet.accept(visitor)
++    end 
++  end
++  describe Parslet::Atoms::Re do
++    let(:parslet) { match['abc'] }
++    it "should call back visitor" do
++      visitor.should_receive(:visit_re).with('[abc]').once
++      
++      parslet.accept(visitor)
++    end 
++  end
++  describe Parslet::Atoms::Sequence do
++    let(:parslet) { str('a') >> str('b') }
++    it "should call back visitor" do
++      visitor.should_receive(:visit_sequence).with(Array).once
++      
++      parslet.accept(visitor)
++    end 
++  end
++  describe Parslet::Atoms::Repetition do
++    let(:parslet) { str('a').repeat(1,2) }
++    it "should call back visitor" do
++      visitor.should_receive(:visit_repetition).with(:repetition, 1, 2, Parslet::Atoms::Base).once
++      
++      parslet.accept(visitor)
++    end 
++  end
++  describe Parslet::Atoms::Alternative do
++    let(:parslet) { str('a') | str('b') }
++    it "should call back visitor" do
++      visitor.should_receive(:visit_alternative).with(Array).once
++      
++      parslet.accept(visitor)
++    end 
++  end
++  describe Parslet::Atoms::Named do
++    let(:parslet) { str('a').as(:a) }
++    it "should call back visitor" do
++      visitor.should_receive(:visit_named).with(:a, Parslet::Atoms::Base).once
++      
++      parslet.accept(visitor)
++    end 
++  end
++  describe Parslet::Atoms::Entity do
++    let(:parslet) { Parslet::Atoms::Entity.new('foo', &lambda {}) }
++    it "should call back visitor" do
++      visitor.should_receive(:visit_entity).with('foo', Proc).once
++      
++      parslet.accept(visitor)
++    end 
++  end
++  describe Parslet::Atoms::Lookahead do
++    let(:parslet) { str('a').absent? }
++    it "should call back visitor" do
++      visitor.should_receive(:visit_lookahead).with(false, Parslet::Atoms::Base).once
++      
++      parslet.accept(visitor)
++    end 
++  end
++  describe "< Parslet::Parser" do
++    let(:parslet) { Parslet::Parser.new }
++    it "calls back to visitor" do
++      visitor.should_receive(:visit_parser).with(:root).once
++      
++      flexmock(parslet, :root => :root)
++      parslet.accept(visitor)
++    end 
++  end
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/parslet/atoms_spec.rb
+@@ -0,0 +1,429 @@
++require 'spec_helper'
++
++require 'timeout'
++require 'parslet'
++
++describe Parslet do
++  def not_parse
++    raise_error(Parslet::ParseFailed)
++  end
++  
++  include Parslet
++  extend Parslet
++
++  def src(str); Parslet::Source.new str; end
++  let(:context) { Parslet::Atoms::Context.new }
++  
++  describe "match('[abc]')" do
++    attr_reader :parslet
++    before(:each) do
++      @parslet = match('[abc]')
++    end
++    
++    it "should parse {a,b,c}" do
++      parslet.parse('a')
++      parslet.parse('b')
++      parslet.parse('c')
++    end 
++    it "should not parse d" do
++      cause = catch_failed_parse {
++        parslet.parse('d')
++      }
++      cause.to_s.should == "Failed to match [abc] at line 1 char 1."
++    end 
++    it "should print as [abc]" do
++      parslet.inspect.should == "[abc]"
++    end 
++  end
++  describe "match(['[a]').repeat(3)" do
++    attr_reader :parslet
++    before(:each) do
++      @parslet = match('[a]').repeat(3)
++    end
++    
++    context "when failing on input 'aa'" do
++      let!(:cause) {
++        catch_failed_parse { parslet.parse('aa') }
++      }
++      it "should have a relevant cause" do
++        cause.to_s.should == "Expected at least 3 of [a] at line 1 char 1."
++      end 
++      it "should have a tree with 2 nodes" do
++        cause.children.should have(1).elements
++      end 
++    end
++    it "should succeed on 'aaa'" do
++      parslet.parse('aaa')
++    end 
++    it "should succeed on many 'a'" do
++      parslet.parse('a'*100)
++    end 
++    it "should inspect as [a]{3, }" do
++      parslet.inspect.should == "[a]{3, }"
++    end
++  end
++  describe "str('foo')" do
++    attr_reader :parslet
++    before(:each) do
++      @parslet = str('foo')
++    end
++    
++    it "should parse 'foo'" do
++      parslet.parse('foo')
++    end
++    it "should not parse 'bar'"  do
++      cause = catch_failed_parse { parslet.parse('bar') }
++      cause.to_s.should == 
++        "Expected \"foo\", but got \"bar\" at line 1 char 1."
++    end
++    it "should inspect as 'foo'" do
++      parslet.inspect.should == "'foo'"
++    end 
++  end
++  describe "str('foo').maybe" do
++    let(:parslet) { str('foo').maybe }
++
++    it "should parse a foo" do
++      parslet.parse('foo')
++    end
++    it "should leave pos untouched if there is no foo" do
++      source = src('bar')
++      parslet.apply(source, context)
++      source.pos.should == 0
++    end
++    it "should inspect as 'foo'?" do
++      parslet.inspect.should == "'foo'?"
++    end 
++    context "when parsing 'foo'" do
++      subject { parslet.parse('foo') }
++      
++      it { should == 'foo' }
++    end
++    context "when parsing ''" do
++      subject { parslet.parse('') } 
++      
++      it { should == '' } 
++    end
++  end
++  describe "str('foo') >> str('bar')" do
++    let(:parslet) { str('foo') >> str('bar') }
++    
++    context "when it fails on input 'foobaz'" do
++      let!(:cause) {
++        catch_failed_parse { parslet.parse('foobaz') }
++      }
++
++      it "should not parse 'foobaz'" do
++        cause.to_s.should == "Failed to match sequence ('foo' 'bar') at line 1 char 4."
++      end
++      it "should have 2 nodes in error tree" do
++        cause.should have(1).children
++      end 
++    end
++    it "should parse 'foobar'" do
++      parslet.parse('foobar')
++    end
++    it "should inspect as ('foo' 'bar')" do
++      parslet.inspect.should == "'foo' 'bar'"
++    end 
++  end
++  describe "str('foo') | str('bar')" do
++    attr_reader :parslet
++    before(:each) do
++      @parslet = str('foo') | str('bar')
++    end
++    
++    context "when failing on input 'baz'" do
++      let!(:cause) {
++        catch_failed_parse { parslet.parse('baz') }
++      }
++
++      it "should have a sensible cause" do
++        cause.to_s.should == "Expected one of ['foo', 'bar'] at line 1 char 1."
++      end   
++      it "should have an error tree with 3 nodes" do
++        cause.should have(2).children
++      end 
++    end
++    
++    it "should accept 'foo'" do
++      parslet.parse('foo')
++    end
++    it "should accept 'bar'" do
++      parslet.parse('bar')
++    end
++    it "should inspect as ('foo' / 'bar')" do
++      parslet.inspect.should == "'foo' / 'bar'"
++    end 
++  end
++  describe "str('foo').present? (positive lookahead)" do
++    attr_reader :parslet
++    before(:each) do
++      @parslet = str('foo').present?
++    end
++    
++    it "should inspect as &'foo'" do
++      parslet.inspect.should == "&'foo'"
++    end 
++    context "when fed 'foo'" do
++      it "should parse" do
++        success, _ = parslet.apply(src('foo'), context)
++        success.should == true
++      end
++      it "should not change input position" do
++        source = src('foo')
++        parslet.apply(source, context)
++        source.pos.should == 0
++      end
++    end
++    context "when fed 'bar'" do
++      it "should not parse" do
++        lambda { parslet.parse('bar') }.should not_parse
++      end
++    end
++    describe "<- #parse" do
++      it "should return nil" do
++        parslet.apply(src('foo'), context).should == [true, nil]
++      end 
++    end
++  end
++  describe "str('foo').absent? (negative lookahead)" do
++    attr_reader :parslet
++    before(:each) do
++      @parslet = str('foo').absent?
++    end
++    
++    it "should inspect as !'foo'" do
++      parslet.inspect.should == "!'foo'"
++    end 
++    context "when fed 'bar'" do
++      it "should parse" do
++        parslet.apply(src('bar'), context).should == [true, nil]
++      end
++      it "should not change input position" do
++        source = src('bar')
++        parslet.apply(source, context)
++        source.pos.should == 0
++      end
++    end
++    context "when fed 'foo'" do
++      it "should not parse" do
++        lambda { parslet.parse('foo') }.should not_parse
++      end
++    end
++  end
++  describe "non greedy matcher combined with greedy matcher (possible loop)" do
++    attr_reader :parslet
++    before(:each) do
++      # repeat will always succeed, since it has a minimum of 0. It will not
++      # modify input position in that case. absent? will, depending on
++      # implementation, match as much as possible and call its inner element
++      # again. This leads to an infinite loop. This example tests for the 
++      # absence of that loop. 
++      @parslet = str('foo').repeat.maybe
++    end
++    
++    it "should not loop infinitely" do
++      lambda {
++        timeout(1) { parslet.parse('bar') }
++      }.should raise_error(Parslet::ParseFailed)
++    end 
++  end
++  describe "any" do
++    attr_reader :parslet
++    before(:each) do
++      @parslet = any
++    end
++    
++    it "should match" do
++      parslet.parse('.')
++    end 
++    it "should consume one char" do
++      source = src('foo')
++      parslet.apply(source, context)
++      source.pos.should == 1
++    end 
++  end
++  describe "eof behaviour" do
++    context "when the pattern just doesn't consume the input" do
++      let (:parslet) { any }
++
++      it "should fail the parse" do
++        cause = catch_failed_parse { parslet.parse('..') }
++        cause.to_s.should == "Don't know what to do with \".\" at line 1 char 2."
++      end 
++    end
++    context "when the pattern doesn't match the input" do
++      let (:parslet) { (str('a')).repeat(1) }
++      attr_reader :exception
++      before(:each) do
++        begin 
++          parslet.parse('a.')
++        rescue => @exception
++        end
++      end
++
++      it "raises Parslet::ParseFailed" do
++        # ParseFailed here, because the input doesn't match the parser grammar. 
++        exception.should be_kind_of(Parslet::ParseFailed)
++      end 
++      it "has the correct error message" do
++        exception.message.should == \
++          "Extra input after last repetition at line 1 char 2."
++      end 
++    end
++  end
++  
++  describe "<- #as(name)" do
++    context "str('foo').as(:bar)" do
++      it "should return :bar => 'foo'" do
++        str('foo').as(:bar).parse('foo').should == { :bar => 'foo' }
++      end 
++    end
++    context "match('[abc]').as(:name)" do
++      it "should return :name => 'b'" do
++        match('[abc]').as(:name).parse('b').should == { :name => 'b' }
++      end 
++    end
++    context "match('[abc]').repeat.as(:name)" do
++      it "should return collated result ('abc')" do
++        match('[abc]').repeat.as(:name).
++          parse('abc').should == { :name => 'abc' }
++      end
++    end
++    context "(str('a').as(:a) >> str('b').as(:b)).as(:c)" do
++      it "should return a hash of hashes" do
++        (str('a').as(:a) >> str('b').as(:b)).as(:c).
++          parse('ab').should == {
++            :c => {
++              :a => 'a', 
++              :b => 'b'
++            }
++          }
++      end 
++    end
++    context "(str('a').as(:a) >> str('ignore') >> str('b').as(:b))" do
++      it "should correctly flatten (leaving out 'ignore')" do
++        (str('a').as(:a) >> str('ignore') >> str('b').as(:b)).
++          parse('aignoreb').should == 
++          {
++            :a => 'a', 
++            :b => 'b'
++          }
++      end
++    end
++    
++    context "(str('a') >> str('ignore') >> str('b')) (no .as(...))" do
++      it "should return simply the original string" do
++        (str('a') >> str('ignore') >> str('b')).
++          parse('aignoreb').should == 'aignoreb'
++      end 
++    end
++    context "str('a').as(:a) >> str('b').as(:a)" do
++      attr_reader :parslet
++      before(:each) do
++        @parslet = str('a').as(:a) >> str('b').as(:a)
++      end
++      
++      it "should issue a warning that a key is being overwritten in merge" do
++        flexmock(parslet).
++          should_receive(:warn).once
++        parslet.parse('ab').should == { :a => 'b' }
++      end
++      it "should return :a => 'b'" do
++        flexmock(parslet).
++          should_receive(:warn)
++          
++        parslet.parse('ab').should == { :a => 'b' }
++      end  
++    end
++    context "str('a').absent?" do
++      it "should return something in merge, even though it is nil" do
++        (str('a').absent? >> str('b').as(:b)).
++          parse('b').should == {:b => 'b'}
++      end
++    end
++    context "str('a').as(:a).repeat" do
++      it "should return an array of subtrees" do
++        str('a').as(:a).repeat.
++          parse('aa').should == [{:a=>'a'}, {:a=>'a'}]
++      end 
++    end
++  end
++  describe "<- #flatten(val)" do
++    def call(val)
++      dummy = str('a')
++      flexmock(dummy, :warn => nil)
++      dummy.flatten(val)
++    end
++    
++    [
++      # In absence of named subtrees: ----------------------------------------
++      # Sequence or Repetition
++      [ [:sequence, 'a', 'b'], 'ab' ], 
++      [ [:repetition, 'a', 'a'], 'aa' ],
++            
++      # Nested inside another node
++      [ [:sequence, [:sequence, 'a', 'b']], 'ab' ],
++      # Combined with lookahead (nil)
++      [ [:sequence, nil, 'a'], 'a' ],
++                  
++      # Including named subtrees ---------------------------------------------
++      # Atom: A named subtree
++      [ {:a=>'a'}, {:a=>'a'} ],
++      # Composition of subtrees
++      [ [:sequence, {:a=>'a'},{:b=>'b'}], {:a=>'a',:b=>'b'} ],
++      # Mixed subtrees :sequence of :repetition yields []
++      [ [:sequence, [:repetition, {:a => 'a'}], {:a => 'a'} ], [{:a=>'a'}, {:a=>'a'}]],
++      [ [:sequence, {:a => 'a'},[:repetition, {:a => 'a'}] ], [{:a=>'a'}, {:a=>'a'}]],
++      [ [:sequence, [:repetition, {:a => 'a'}],[:repetition, {:a => 'a'}] ], [{:a=>'a'}, {:a=>'a'}]],
++      # Repetition
++      [ [:repetition, [:repetition, {:a=>'a'}], [:repetition, {:a=>'a'}]], 
++        [{:a => 'a'}, {:a => 'a'}]],
++      [ [:repetition, {:a=>'a'}, 'a', {:a=>'a'}], [{:a=>'a'}, {:a=>'a'}]],
++      [ [:repetition, {:a=>'a'}, [:repetition, {:b=>'b'}]], [{:a=>'a'}] ],
++      
++      # Some random samples --------------------------------------------------
++      [ [:sequence, {:a => :b, :b => :c}], {:a=>:b, :b=>:c} ], 
++      [ [:sequence, {:a => :b}, 'a', {:c=>:d}], {:a => :b, :c=>:d} ], 
++      [ [:repetition, {:a => :b}, 'a', {:c=>:d}], [{:a => :b}, {:c=>:d}] ], 
++      [ [:sequence, {:a => :b}, {:a=>:d}], {:a => :d} ], 
++      [ [:sequence, {:a=>:b}, [:sequence, [:sequence, "\n", nil]]], {:a=>:b} ], 
++      [ [:sequence, nil, " "], ' ' ], 
++    ].each do |input, output|
++      it "should transform #{input.inspect} to #{output.inspect}" do
++        call(input).should == output
++      end
++    end
++  end
++
++  describe "combinations thereof (regression)" do
++    sucess =[
++      [(str('a').repeat >> str('b').repeat), 'aaabbb'] 
++    ].each do |(parslet, input)|
++      describe "#{parslet.inspect} applied to #{input.inspect}" do
++        it "should parse successfully" do
++          parslet.parse(input)
++        end
++      end 
++    end
++
++    inspection=[
++      [str('a'),                              "'a'"                 ], 
++      [(str('a') | str('b')).maybe,           "('a' / 'b')?"        ], 
++      [(str('a') >> str('b')).maybe,          "('a' 'b')?"          ], 
++      [str('a').maybe.maybe,                  "'a'??"               ], 
++      [(str('a')>>str('b')).maybe.maybe,      "('a' 'b')??"         ], 
++      [(str('a') >> (str('b') | str('c'))),   "'a' ('b' / 'c')"], 
++      
++      [str('a') >> str('b').repeat,           "'a' 'b'{0, }"        ], 
++      [(str('a')>>str('b')).repeat,           "('a' 'b'){0, }"      ]  
++    ].each do |(parslet, inspect_output)|
++      context "regression for #{parslet.inspect}" do
++        it "should inspect correctly as #{inspect_output}" do
++          parslet.inspect.should == inspect_output
++        end 
++      end
++    end
++  end
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/parslet/convenience_spec.rb
+@@ -0,0 +1,48 @@
++require 'spec_helper'
++
++describe 'parslet/convenience' do
++  require 'parslet/convenience'
++  include Parslet
++  
++  class FooParser < Parslet::Parser
++    rule(:foo) { str('foo') }
++    root(:foo)
++  end
++  
++  describe 'parse_with_debug' do
++    let(:parser) { flexmock FooParser.new }
++    context 'internal' do
++      before(:each) do
++        # Suppress output.
++        #
++        parser.should_receive(:puts)
++      end
++      it 'should exist' do
++        lambda { parser.parse_with_debug('anything') }.should_not raise_error(NoMethodError)
++      end
++      it 'should catch ParseFailed exceptions' do
++        lambda { parser.parse_with_debug('bar') }.should_not raise_error(Parslet::ParseFailed)
++      end
++      it 'should parse correct input like #parse' do
++        lambda { parser.parse_with_debug('foo') }.should_not raise_error
++      end
++    end
++    context 'output' do
++      it 'should puts once for tree output' do
++        parser.should_receive(:puts).once
++        
++        parser.parse_with_debug('incorrect')
++      end
++      it "should puts once for the error on unconsumed input" do
++        parser.should_receive(:puts).once
++
++        parser.parse_with_debug('foobar')
++      end 
++    end
++    
++    it "should work for all parslets" do
++      str('foo').parse_with_debug('foo')
++      match['bar'].parse_with_debug('a')
++    end 
++  end
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/parslet/error_reporter/deepest_spec.rb
+@@ -0,0 +1,73 @@
++require 'spec_helper'
++
++describe Parslet::ErrorReporter::Deepest do
++  let(:reporter) { described_class.new }
++  let(:fake_source) { flexmock('source') }
++  
++  describe '#err' do
++    before(:each) { fake_source.should_receive(
++      :pos => 13, 
++      :line_and_column => [1,1]) }
++    
++    it "returns the deepest cause" do
++      flexmock(reporter).
++        should_receive(:deepest).and_return(:deepest)
++      reporter.err('parslet', fake_source, 'message').
++        should == :deepest
++    end 
++  end
++  describe '#err_at' do
++    before(:each) { fake_source.should_receive(
++      :pos => 13, 
++      :line_and_column => [1,1]) }
++
++    it "returns the deepest cause" do
++      flexmock(reporter).
++        should_receive(:deepest).and_return(:deepest)
++      reporter.err('parslet', fake_source, 'message', 13).
++        should == :deepest
++    end
++  end
++  describe '#deepest(cause)' do
++    def fake_cause(pos=13, children=nil)
++      flexmock('cause' + pos.to_s, :pos => pos, :children => children)
++    end
++    
++    context "when there is no deepest cause yet" do
++      let(:cause) { fake_cause }
++      it "returns the given cause" do
++        reporter.deepest(cause).should == cause
++      end
++    end
++    context "when the previous cause is deeper (no relationship)" do
++      let(:previous) { fake_cause }
++      before(:each) { 
++        reporter.deepest(previous) }
++      
++      it "returns the previous cause" do
++        reporter.deepest(fake_cause(12)).
++          should == previous
++      end 
++    end
++    context "when the previous cause is deeper (child)" do
++      let(:previous) { fake_cause }
++      before(:each) { 
++        reporter.deepest(previous) }
++        
++      it "returns the given cause" do
++        given = fake_cause(12, [previous])
++        reporter.deepest(given).should == given
++      end 
++    end
++    context "when the previous cause is shallower" do
++      before(:each) { 
++        reporter.deepest(fake_cause) }
++      
++      it "stores the cause as deepest" do
++        deeper = fake_cause(14)
++        reporter.deepest(deeper)
++        reporter.deepest_cause.should == deeper
++      end
++    end
++  end
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/parslet/error_reporter/tree_spec.rb
+@@ -0,0 +1,7 @@
++require 'spec_helper'
++
++require 'parslet/error_reporter'
++
++describe Parslet::ErrorReporter::Tree do
++  
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/parslet/export_spec.rb
+@@ -0,0 +1,67 @@
++require 'spec_helper'
++
++describe Parslet::Parser, "exporting to other lingos" do
++  class MiniLisp < Parslet::Parser
++    root :expression
++    rule(:expression) {
++      space? >> str('(') >> space? >> body >> str(')')
++    }
++    
++    rule(:body) {
++      (expression | identifier | float | integer | string).repeat.as(:exp)
++    }
++    
++    rule(:space) {
++      match('\s').repeat(1)
++    }
++    rule(:space?) {
++      space.maybe
++    }
++    
++    rule(:identifier) { 
++      (match('[a-zA-Z=*]') >> match('[a-zA-Z=*_]').repeat).as(:identifier) >> space?
++    }
++    
++    rule(:float) { 
++      (
++        integer >> (
++          str('.') >> match('[0-9]').repeat(1) |
++          str('e') >> match('[0-9]').repeat(1)
++        ).as(:e)
++      ).as(:float) >> space?
++    }
++    
++    rule(:integer) {
++      ((str('+') | str('-')).maybe >> match("[0-9]").repeat(1)).as(:integer) >> space?
++    }
++    
++    rule(:string) {
++      str('"') >> (
++        str('\\') >> any |
++        str('"').absent? >> any 
++      ).repeat.as(:string) >> str('"') >> space?
++    }
++  end
++
++  # I only update the files once I've verified the new syntax to work with 
++  # the respective tools. This is more an acceptance test than a real spec. 
++
++  describe "<- #to_citrus" do
++    let(:citrus) { File.read(
++      File.join(File.dirname(__FILE__), 'minilisp.citrus'))
++    }
++    it "should be valid citrus syntax" do
++      # puts MiniLisp.new.to_citrus
++      MiniLisp.new.to_citrus.should == citrus 
++    end 
++  end
++  describe "<- #to_treetop" do
++    let(:treetop) { File.read(
++      File.join(File.dirname(__FILE__), 'minilisp.tt'))
++    }
++    it "should be valid treetop syntax" do
++      # puts MiniLisp.new.to_treetop
++      MiniLisp.new.to_treetop.should == treetop
++    end 
++  end
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/parslet/expression/treetop_spec.rb
+@@ -0,0 +1,74 @@
++require 'spec_helper'
++
++require 'parslet'
++
++describe Parslet::Expression::Treetop do
++  include Parslet
++
++  describe "positive samples" do
++    [ # pattern             # input
++      "'abc'",              'abc', 
++      "...",                'abc', 
++      "[1-4]",              '3',
++      
++      "'abc'?",             'abc', 
++      "'abc'?",             '', 
++      
++      "('abc')",            'abc', 
++      
++      "'a' 'b'",            'ab', 
++      "'a' ('b')",          'ab', 
++      
++      "'a' / 'b'",          'a', 
++      "'a' / 'b'",          'b', 
++      
++      "'a'*",               'aaa', 
++      "'a'*",               '', 
++
++      "'a'+",               'aa', 
++      "'a'+",               'a', 
++      
++      "'a'{1,2}",           'a',
++      "'a'{1,2}",           'aa',
++
++      "'a'{1,}",            'a',
++      "'a'{1,}",            'aa',
++
++      "'a'{,2}",            '',
++      "'a'{,2}",            'a',
++      "'a'{,2}",            'aa',
++    ].each_slice(2) do |pattern, input|
++      context "exp(#{pattern.inspect})" do
++        let(:parslet) { exp(pattern) }
++        subject { parslet }
++        it { should parse(input) }
++        context "string representation" do
++          subject { exp(parslet.to_s) }
++          it { should parse(input, :trace => true) }
++        end
++      end
++    end
++  end
++  describe "negative samples" do
++    [ # pattern             # input
++      "'abc'",              'cba', 
++      "[1-4]",              '5',
++      
++      "'a' / 'b'",          'c', 
++      
++      "'a'+",               '',
++      
++      "'a'{1,2}",           '',
++      "'a'{1,2}",           'aaa',
++      
++      "'a'{1,}",            '',
++
++      "'a'{,2}",            'aaa',
++    ].each_slice(2) do |pattern, input|
++      context "exp(#{pattern.inspect})" do
++        subject { exp(pattern) }
++        it { should_not parse(input) }
++      end
++    end
++  end
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/parslet/minilisp.citrus
+@@ -0,0 +1,29 @@
++grammar MiniLisp
++  rule root
++    (expression)
++  end
++  rule expression
++    ((space_p) "(" (space_p) (body) ")")
++  end
++  rule space_p
++    (space)0*1
++  end
++  rule body
++    ((expression) | (identifier) | (float) | (integer) | (string))0*
++  end
++  rule space
++    \s1*
++  end
++  rule identifier
++    (([a-zA-Z=*] [a-zA-Z=*_]0*) (space_p))
++  end
++  rule float
++    (((integer) (("." [0-9]1*) | ("e" [0-9]1*))) (space_p))
++  end
++  rule integer
++    ((("+" | "-")0*1 [0-9]1*) (space_p))
++  end
++  rule string
++    ("\"" (("\\" .) | (!"\"" .))0* "\"" (space_p))
++  end
++end
+--- /dev/null
++++ ruby-parslet/spec/parslet/minilisp.tt
+@@ -0,0 +1,29 @@
++grammar MiniLisp
++  rule root
++    (expression)
++  end
++  rule expression
++    ((space_p) "(" (space_p) (body) ")")
++  end
++  rule space_p
++    (space)0..1
++  end
++  rule body
++    ((expression) / (identifier) / (float) / (integer) / (string))0..
++  end
++  rule space
++    \s1..
++  end
++  rule identifier
++    (([a-zA-Z=*] [a-zA-Z=*_]0..) (space_p))
++  end
++  rule float
++    (((integer) (("." [0-9]1..) / ("e" [0-9]1..))) (space_p))
++  end
++  rule integer
++    ((("+" / "-")0..1 [0-9]1..) (space_p))
++  end
++  rule string
++    ("\"" (("\\" .) / (!"\"" .))0.. "\"" (space_p))
++  end
++end
+--- /dev/null
++++ ruby-parslet/spec/parslet/parser_spec.rb
+@@ -0,0 +1,31 @@
++require 'spec_helper'
++
++describe Parslet::Parser do
++  include Parslet
++  class FooParser < Parslet::Parser
++    rule(:foo) { str('foo') }
++    root(:foo)
++  end
++  
++  describe "<- .root" do
++    parser = Class.new(Parslet::Parser)
++    parser.root :root_parslet
++    
++    it "should have defined a 'root' method, returning the root" do
++      parser_instance = parser.new
++      flexmock(parser_instance).should_receive(:root_parslet => :answer)
++      
++      parser_instance.root.should == :answer
++    end 
++  end
++  it "should parse 'foo'" do
++    FooParser.new.parse('foo').should == 'foo'
++  end 
++  context "composition" do
++    let(:parser) { FooParser.new }
++    it "should allow concatenation" do
++      composite = parser >> str('bar')
++      composite.should parse('foobar')
++    end
++  end
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/parslet/parslet_spec.rb
+@@ -0,0 +1,38 @@
++require 'spec_helper'
++
++describe Parslet do
++  include Parslet
++  
++  describe Parslet::ParseFailed do
++    it "should be caught by an empty rescue" do
++      begin
++        raise Parslet::ParseFailed
++      rescue
++        # Success! Ignore this.
++      end
++    end 
++  end
++  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
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/parslet/pattern_spec.rb
+@@ -0,0 +1,268 @@
++require 'spec_helper'
++
++require 'parslet'
++
++describe Parslet::Pattern do
++  include Parslet
++  
++  # These two factory methods help make the specs more robust to interface
++  # changes. They also help to label trees (t) and patterns (p).
++  def p(pattern)
++    Parslet::Pattern.new(pattern)
++  end
++  def t(obj)
++    obj
++  end
++  
++  # Tries to match pattern to the tree, and verifies the bindings hash. Don't
++  # use this for new examples.
++  #
++  RSpec::Matchers.define :match_with_bind do |pattern, exp_bindings|
++    failure_message_for_should do |tree|
++      "expected #{pattern.inspect} to match #{tree.inspect}, but didn't. (block wasn't called or not correctly)"
++    end
++    match do |tree|
++      bindings = Parslet::Pattern.new(pattern).match(tree)
++      bindings && bindings == exp_bindings
++    end
++  end
++
++  # This is the more modern version of verifying a match: (uses 'exp'
++  # implicitly). Checks for a match of pattern in +exp+ and yields the
++  # matched variables.
++  #
++  def with_match_locals(pattern, &block) 
++    bindings = p(pattern).match(exp)
++    bindings.should_not be_nil
++    
++    block.call(bindings) if block
++  end
++  
++  # Can't use #match here, so I went to the Thesaurus.
++  #
++  RSpec::Matchers.define :detect do |pattern|
++    match do |tree|
++      bindings = Parslet::Pattern.new(pattern).match(tree)
++
++      bindings ? true : false
++    end
++  end
++  
++  describe "<- #match" do
++    context "injecting bindings" do
++      let(:pattern) { p(simple(:x)) }
++      
++      it "should not modify the original bindings hash" do
++        h = {}
++        b=pattern.match('a', h)
++        h.size.should == 0
++        b.size.should == 1
++      end
++      it "should return nil when no match succeeds" do
++        pattern.match([], :foo => :bar).should be_nil
++      end
++      context "when matching simple(:x) against 'a'" do
++        let(:bindings) { pattern.match(t('a'), :foo => :bar) }
++        
++        before(:each) { bindings.should_not be_nil }
++        it "should return the injected bindings" do
++          bindings[:foo].should == :bar
++        end
++        it "should return the new bindings" do  
++          bindings[:x].should == 'a'
++        end
++      end
++    end
++    context "simple strings" do
++      let(:exp) { 'aaaa' }
++
++      it "should match simple strings" do
++        exp.should match_with_bind(simple(:x), :x => 'aaaa')
++      end 
++    end
++    context "simple hash {:a => 'b'}" do
++      attr_reader :exp
++      before(:each) do
++        @exp = t(:a => 'b')
++      end
++
++      it "should not match {:a => simple(:x), :b => simple(:y)}" do
++        exp.should_not detect(:a => simple(:x), :b => simple(:y))
++      end
++      it "should match {:a => simple(:x)}, binding 'x' to the first argument" do
++        exp.should match_with_bind({:a => simple(:x)}, :x => 'b')
++      end 
++      it "should match {:a => 'b'} with no binds" do
++        exp.should match_with_bind({:a => 'b'}, {})
++      end 
++    end
++    context "a more complex hash {:a => {:b => 'c'}}" do
++      attr_reader :exp
++      before(:each) do
++        @exp = t(:a => {:b => 'c'})
++      end
++      
++      it "should match wholly with {:a => {:b => simple(:x)}}" do
++        exp.should match_with_bind({:a => {:b => simple(:x)}}, :x => 'c')
++      end
++      it "should match wholly with {:a => subtree(:t)}" do
++        with_match_locals(:a => subtree(:t)) do |dict|
++          dict[:t].should == {:b => 'c'}
++        end
++      end
++      it "should not bind subtrees to variables in {:a => simple(:x)}" do
++        p(:a => simple(:x)).should_not detect(exp)
++      end
++    end
++    context "a more complex hash {:a => 'a', :b => 'b'}" do
++      attr_reader :exp
++      before(:each) do
++        @exp = t({:a => 'a', :b => 'b'})
++      end
++
++      it "should not match partially" do
++        Parslet::Pattern.new(:a => simple(:x)).match(exp).should be_nil
++      end 
++      it "should match completely" do
++        exp.should match_with_bind({:a => simple(:x), :b => simple(:y)}, 
++          :x => 'a', 
++          :y => 'b')
++      end 
++    end
++    context "an array of 'a', 'b', 'c'" do
++      let(:exp) { ['a', 'b', 'c'] }
++
++      it "should match all elements at once" do
++        exp.should match_with_bind(
++          [simple(:x), simple(:y), simple(:z)], 
++          :x => 'a', :y => 'b', :z => 'c')
++      end 
++    end
++    context "{:a => 'a', :b => 'b'}" do
++      attr_reader :exp
++      before(:each) do
++        @exp = t(:a => 'a', :b => 'b')
++      end
++
++      it "should match both elements simple(:x), simple(:y)" do
++        exp.should match_with_bind(
++          {:a => simple(:x), :b => simple(:y)}, 
++          :x => 'a', :y => 'b')
++      end
++      it "should not match a constrained match (simple(:x) != simple(:y))"  do
++        exp.should_not detect({:a => simple(:x), :b => simple(:x)})
++      end
++    end
++    context "{:a => 'a', :b => 'a'}" do
++      attr_reader :exp
++      before(:each) do
++        @exp = t(:a => 'a', :b => 'a')
++      end
++
++      it "should match constrained pattern" do
++        exp.should match_with_bind(
++          {:a => simple(:x), :b => simple(:x)}, 
++          :x => 'a')
++      end
++    end
++    context "{:sub1 => {:a => 'a'}, :sub2 => {:a => 'a'}}" do
++      attr_reader :exp
++      before(:each) do
++        @exp = t({
++          :sub1 => {:a => 'a'}, 
++          :sub2 => {:a => 'a'} 
++        })
++      end
++
++      it "should verify constraints over several subtrees" do
++        exp.should match_with_bind({
++          :sub1 => {:a => simple(:x)}, 
++          :sub2 => {:a => simple(:x)} 
++        }, :x => 'a')
++      end
++      it "should return both bind variables simple(:x), simple(:y)" do
++        exp.should match_with_bind({
++          :sub1 => {:a => simple(:x)}, 
++          :sub2 => {:a => simple(:y)} 
++        }, :x => 'a', :y => 'a')
++      end  
++    end
++    context "{:sub1 => {:a => 'a'}, :sub2 => {:a => 'b'}}" do
++      attr_reader :exp
++      before(:each) do
++        @exp = t({
++          :sub1 => {:a => 'a'}, 
++          :sub2 => {:a => 'b'} 
++        })
++      end
++
++      it "should verify constraints over several subtrees" do
++        exp.should_not match_with_bind({
++          :sub1 => {:a => simple(:x)}, 
++          :sub2 => {:a => simple(:x)} 
++        }, :x => 'a')
++      end
++      it "should return both bind variables simple(:x), simple(:y)" do
++        exp.should match_with_bind({
++          :sub1 => {:a => simple(:x)}, 
++          :sub2 => {:a => simple(:y)} 
++        }, :x => 'a', :y => 'b')
++      end  
++    end
++    context "[{:a => 'x'}, {:a => 'y'}]" do
++      attr_reader :exp  
++      before(:each) do
++        @exp = t([{:a => 'x'}, {:a => 'y'}])
++      end
++      
++      it "should not match sequence(:x) (as a whole)" do
++        exp.should_not detect(sequence(:x))
++      end
++    end
++    context "['x', 'y', 'z']" do
++      attr_reader :exp  
++      before(:each) do
++        @exp = t(['x', 'y', 'z'])
++      end
++
++      it "should match [simple(:x), simple(:y), simple(:z)]" do
++        with_match_locals([simple(:x), simple(:y), simple(:z)]) do |dict|
++          dict[:x].should == 'x'
++          dict[:y].should == 'y'
++          dict[:z].should == 'z'
++        end
++      end
++      it "should match %w(x y z)" do
++        exp.should match_with_bind(%w(x y z), { })
++      end 
++      it "should not match [simple(:x), simple(:y), simple(:x)]" do
++        exp.should_not detect([simple(:x), simple(:y), simple(:x)])
++      end
++      it "should not match [simple(:x), simple(:y)]" do
++        exp.should_not detect([simple(:x), simple(:y), simple(:x)])
++      end
++      it "should match sequence(:x) (as array)" do
++        exp.should match_with_bind(sequence(:x), :x => ['x', 'y', 'z'])
++      end
++    end
++    context "{:a => [1,2,3]}" do
++      attr_reader :exp  
++      before(:each) do
++        @exp = t(:a => [1,2,3])
++      end
++
++      it "should match :a => sequence(:x) (binding x to the whole array)" do
++        exp.should match_with_bind({:a => sequence(:x)}, {:x => [1,2,3]})
++      end
++    end
++    context "with differently ordered hashes" do
++      it "should still match" do
++        t(:a => 'a', :b => 'b').should detect(:a => 'a', :b => 'b')
++        t(:a => 'a', :b => 'b').should detect(:b => 'b', :a => 'a')
++
++        t(:b => 'b', :a => 'a').should detect(:b => 'b', :a => 'a')
++        t(:b => 'b', :a => 'a').should detect(:a => 'a', :b => 'b')
++      end 
++    end
++  end
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/parslet/rig/rspec_spec.rb
+@@ -0,0 +1,35 @@
++require 'spec_helper'
++require 'parslet/rig/rspec'
++
++describe 'rspec integration' do
++  include Parslet
++  subject { str('example') }
++
++  it { should parse('example') }
++  it { should_not parse('foo') }
++  it { should parse('example').as('example') }
++  it { should_not parse('foo').as('example') }
++  it { should_not parse('example').as('foo') }
++
++  it { str('foo').as(:bar).should parse('foo').as({:bar => 'foo'}) }
++  it { str('foo').as(:bar).should_not parse('foo').as({:b => 'f'}) }
++
++  it 'accepts a block to assert more specific details about the parsing output' do
++    str('foo').as(:bar).should(parse('foo').as { |output|
++      output.should have_key(:bar)
++      output.values.first.should == 'foo'
++    })
++  end
++
++  # Uncomment to test error messages manually: 
++  # it { str('foo').should parse('foo', :trace => true).as('bar') }
++  # it { str('foo').should parse('food', :trace => true) }
++  # it { str('foo').should_not parse('foo', :trace => true).as('foo') }
++  # it { str('foo').should_not parse('foo', :trace => true) }
++  # it 'accepts a block to assert more specific details about the parsing output' do
++  #   str('foo').as(:bar).should(parse('foo', :trace => true).as { |output|
++  #     output.should_not have_key(:bar)
++  #   })
++  # end
++  
++end
+--- /dev/null
++++ ruby-parslet/spec/parslet/scope_spec.rb
+@@ -0,0 +1,45 @@
++require 'spec_helper'
++
++describe Parslet::Scope do
++  let(:scope) { described_class.new }
++  
++  describe 'simple store/retrieve' do
++    before(:each) { scope[:foo] = :bar }
++    it "allows storing objects" do
++      scope[:obj] = 42
++    end 
++    it "raises on access of empty slots" do
++      expect {
++        scope[:empty]
++      }.to raise_error(Parslet::Scope::NotFound)
++    end 
++    it "allows retrieval of stored values" do
++      scope[:foo].should == :bar
++    end 
++  end
++  
++  describe 'scoping' do
++    before(:each) { scope[:depth] = 1 }
++    before(:each) { scope.push }
++    
++    let(:depth) { scope[:depth] }
++    subject { depth }
++    
++    it { should == 1 }
++    describe 'after a push' do
++      before(:each) { scope.push }
++      it { should == 1 }
++      
++      describe 'and reassign' do
++        before(:each) { scope[:depth] = 2 }
++        
++        it { should == 2 }
++
++        describe 'and a pop' do
++          before(:each) { scope.pop }
++          it { should == 1 }
++        end
++      end
++    end
++  end
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/parslet/slice_spec.rb
+@@ -0,0 +1,134 @@
++require 'spec_helper'
++
++describe Parslet::Slice do
++  describe "construction" do
++    it "should construct from an offset and a string" do
++      described_class.new('foobar', 40)
++    end
++  end
++  context "('foobar', 40)" do
++    let(:slice) { described_class.new('foobar', 40) }
++    describe "comparison" do
++      it "should be equal to other slices with the same attributes" do
++        other = described_class.new('foobar', 40)
++        slice.should == other
++        other.should == slice
++      end 
++      it "should be equal to other slices (offset is irrelevant for comparison)" do
++        other = described_class.new('foobar', 41)
++        slice.should == other
++        other.should == slice
++      end 
++      it "should be equal to a string with the same content" do
++        slice.should == 'foobar'
++      end
++      it "should be equal to a string (inversed operands)" do
++        'foobar'.should == slice
++      end 
++      it "should not be equal to a string" do
++        slice.should_not equal('foobar')
++      end 
++      it "should not be eql to a string" do
++        slice.should_not eql('foobar')
++      end 
++      it "should not hash to the same number" do
++        slice.hash.should_not == 'foobar'.hash
++      end 
++    end
++    describe "offset" do
++      it "should return the associated offset" do
++        slice.offset.should == 40
++      end
++      it "should fail to return a line and column" do
++        lambda {
++          slice.line_and_column
++        }.should raise_error(ArgumentError)
++      end 
++      
++      context "when constructed with a source" do
++        let(:slice) { described_class.new(
++          'foobar', 40,  
++          flexmock(:cache, :line_and_column => [13, 14])) }
++        it "should return proper line and column" do
++          slice.line_and_column.should == [13, 14]
++        end
++      end
++    end
++    describe "string methods" do
++      describe "matching" do
++        it "should match as a string would" do
++          slice.should match(/bar/)
++          slice.should match(/foo/)
++
++          md = slice.match(/f(o)o/)
++          md.captures.first.should == 'o'
++        end
++      end
++      describe "<- #size" do
++        subject { slice.size }
++        it { should == 6 } 
++      end
++      describe "<- #+" do
++        let(:other) { described_class.new('baz', 10) }
++        subject { slice + other }
++        
++        it "should concat like string does" do
++          subject.size.should == 9
++          subject.should == 'foobarbaz'
++          subject.offset.should == 40
++        end 
++      end
++    end
++    describe "conversion" do
++      describe "<- #to_slice" do
++        it "should return self" do
++          slice.to_slice.should eq(slice)
++        end 
++      end
++      describe "<- #to_sym" do
++        it "should return :foobar" do
++          slice.to_sym.should == :foobar
++        end 
++      end
++      describe "cast to Float" do
++        it "should return a float" do
++          Float(described_class.new('1.345', 11)).should == 1.345
++        end 
++      end
++      describe "cast to Integer" do
++        it "should cast to integer as a string would" do
++          s = described_class.new('1234', 40)
++          Integer(s).should == 1234
++          s.to_i.should == 1234
++        end 
++        it "should fail when Integer would fail on a string" do
++          lambda { Integer(slice) }.should raise_error
++        end 
++        it "should turn into zero when a string would" do
++          slice.to_i.should == 0
++        end 
++      end
++    end
++    describe "inspection and string conversion" do
++      describe "#inspect" do
++        subject { slice.inspect }
++        it { should == '"foobar"@40' }
++      end
++      describe "#to_s" do
++        subject { slice.to_s }
++        it { should == 'foobar' }
++      end
++    end
++    describe "serializability" do
++      it "should serialize" do
++        Marshal.dump(slice)
++      end
++      context "when storing a line cache" do
++        let(:slice) { described_class.new('foobar', 40, Parslet::Source::LineCache.new()) }
++        it "should serialize" do
++          Marshal.dump(slice)
++        end
++      end
++    end
++  end
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/parslet/source/line_cache_spec.rb
+@@ -0,0 +1,39 @@
++require 'spec_helper'
++
++describe Parslet::Source::RangeSearch do
++  describe "<- #lbound" do
++    context "for a simple array" do
++      let(:ary) { [10, 20, 30, 40, 50] }
++      before(:each) { ary.extend Parslet::Source::RangeSearch }
++
++      it "should return correct answers for numbers not in the array" do
++        ary.lbound(5).should == 0
++        ary.lbound(15).should == 1
++        ary.lbound(25).should == 2
++        ary.lbound(35).should == 3
++        ary.lbound(45).should == 4
++      end
++      it "should return correct answers for numbers in the array" do
++        ary.lbound(10).should == 1
++        ary.lbound(20).should == 2
++        ary.lbound(30).should == 3
++        ary.lbound(40).should == 4
++      end
++      it "should cover right edge case" do
++        ary.lbound(50).should be_nil
++        ary.lbound(51).should be_nil
++      end 
++      it "should cover left edge case" do
++        ary.lbound(0).should == 0
++      end
++    end
++    context "for an empty array" do
++      let(:ary) { [] }
++      before(:each) { ary.extend Parslet::Source::RangeSearch }
++
++      it "should return nil" do
++        ary.lbound(1).should be_nil
++      end 
++    end
++  end
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/parslet/source_spec.rb
+@@ -0,0 +1,154 @@
++# Encoding: UTF-8
++
++require 'spec_helper'
++
++describe Parslet::Source do
++  describe "using simple input" do
++    let(:str)     { "a"*100 + "\n" + "a"*100 + "\n" }
++    let(:source)  { described_class.new(str) }
++  
++    describe "<- #read(n)" do
++      it "should not raise error when the return value is nil" do
++        described_class.new('').consume(1)
++      end 
++      it "should return 100 'a's when reading 100 chars" do
++        source.consume(100).should == 'a'*100
++      end
++    end
++    describe "<- #chars_left" do
++      subject { source.chars_left }
++  
++      it { should == 202 }
++      context "after depleting the source" do
++        before(:each) { source.consume(10000) }
++  
++        it { should == 0 }
++      end
++    end
++    describe "<- #pos" do
++      subject { source.pos }
++  
++      it { should == 0 }
++      context "after reading a few bytes" do
++        it "should still be correct" do
++          pos = 0
++          10.times do
++            pos += (n = rand(10)+1)
++            source.consume(n)
++  
++            source.pos.should == pos
++          end
++        end 
++      end
++    end
++    describe "<- #pos=(n)" do
++      subject { source.pos }
++      10.times do
++        pos = rand(200)
++        context "setting position #{pos}" do
++          before(:each) { source.pos = pos }
++  
++          it { should == pos }
++        end
++      end
++    end
++    describe "<- #column & #line" do
++      subject { source.line_and_column }
++  
++      it { should == [1,1] }
++  
++      context "on the first line" do
++        it "should increase column with every read" do
++          10.times do |i|
++            source.line_and_column.last.should == 1+i
++            source.consume(1)
++          end
++        end 
++      end
++      context "on the second line" do
++        before(:each) { source.consume(101) }
++        it { should == [2, 1]}
++      end
++      context "after reading everything" do
++        before(:each) { source.consume(10000) }
++  
++        context "when seeking to 9" do
++          before(:each) { source.pos = 9 }
++          it { should == [1, 10] }
++        end
++        context "when seeking to 100" do
++          before(:each) { source.pos = 100 }
++          it { should == [1, 101] }
++        end
++        context "when seeking to 101" do
++          before(:each) { source.pos = 101 }
++          it { should == [2, 1] }
++        end
++        context "when seeking to 102" do
++          before(:each) { source.pos = 102 }
++          it { should == [2, 2] }
++        end
++        context "when seeking beyond eof" do
++          it "should not throw an error" do
++            source.pos = 1000
++          end 
++        end
++      end
++      context "reading char by char, storing the results" do
++        attr_reader :results
++        before(:each) { 
++          @results = {}
++          while source.chars_left>0
++            pos = source.pos
++            @results[pos] = source.line_and_column
++            source.consume(1)
++          end
++  
++          @results.should have(202).entries
++          @results
++        }
++  
++        context "when using pos argument" do
++          it "should return the same results" do
++            results.each do |pos, result|
++              source.line_and_column(pos).should == result
++            end
++          end 
++        end
++        it "should give the same results when seeking" do
++          results.each do |pos, result|
++            source.pos = pos
++            source.line_and_column.should == result
++          end
++        end
++        it "should give the same results when reading" do
++          cur = source.pos = 0
++          while source.chars_left>0
++            source.line_and_column.should == results[cur]
++            cur += 1
++            source.consume(1)
++          end
++        end 
++      end
++    end
++    
++  end
++  
++  describe "reading encoded input", :ruby => 1.9 do
++    let(:source) { described_class.new("éö変わる") }
++    
++    it "should read characters, not bytes" do
++      source.should match("é")
++      source.consume(1)
++      
++      source.should match("ö")
++      source.consume(1)
++      
++      source.should match("変")
++      source.consume(1)
++      
++      source.consume(2)
++      source.chars_left.should == 0
++    end 
++  end
++end
+--- /dev/null
++++ ruby-parslet/spec/parslet/transform/context_spec.rb
+@@ -0,0 +1,35 @@
++require 'spec_helper'
++
++describe Parslet::Transform::Context do
++  def context(*args)
++    described_class.new(*args)
++  end
++  
++  it "binds hash keys as variable like things" do
++    context(:a => 'value').instance_eval { a }.
++      should == 'value'
++  end
++  describe 'when a method in BlankSlate is inherited from the environment somehow' do
++    before(:each) { BlankSlate.send(:define_method, :a) { 'c' } }
++    after(:each) { BlankSlate.send(:undef_method, :a) }
++    
++    it "masks what is already on blank slate" do
++      context(:a => 'b').instance_eval { a }.
++        should == 'b'
++    end  
++  end
++  it "should not reveal define_singleton_method for all users of blankslate, just for us" do
++    expect {
++      BlankSlate.new.instance_eval {
++        define_singleton_method(:foo) { 'foo' }
++      }
++    }.to raise_error(NoMethodError)
++  end 
++  it "one contexts variables aren't the next ones" do
++    ca = context(:a => 'b')
++    cb = context(:b => 'c')
++
++    ca.methods.should_not include(:b)
++    cb.methods.should_not include(:a)
++  end
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/parslet/transform_spec.rb
+@@ -0,0 +1,144 @@
++require 'spec_helper'
++
++require 'parslet'
++
++describe Parslet::Transform do
++  include Parslet
++  
++  let(:transform) { Parslet::Transform.new }
++  attr_reader :transform
++  before(:each) do
++    @transform = Parslet::Transform.new
++  end
++  
++  class A < Struct.new(:elt); end
++  class B < Struct.new(:elt); end
++  class C < Struct.new(:elt); end
++  class Bi < Struct.new(:a, :b); end
++
++  describe "delayed construction" do
++    context "given simple(:x) => A.new(x)" do
++      before(:each) do
++        transform.rule(simple(:x)) { |d| A.new(d[:x]) }
++      end
++
++      it "should transform 'a' into A.new('a')" do
++        transform.apply('a').should == A.new('a')
++      end 
++      it "should transform ['a', 'b'] into [A.new('a'), A.new('b')]" do
++        transform.apply(['a', 'b']).should == 
++          [A.new('a'), A.new('b')]
++      end
++    end
++    context "given rules on {:a => simple(:x)} and {:b => :_x}" do
++      before(:each) do
++        transform.rule(:a => simple(:x)) { |d| A.new(d[:x]) }
++        transform.rule(:b => simple(:x)) { |d| B.new(d[:x]) }
++      end
++
++      it "should transform {:d=>{:b=>'c'}} into d => B('c')" do
++        transform.apply({:d=>{:b=>'c'}}).should == {:d => B.new('c')}
++      end
++      it "should transform {:a=>{:b=>'c'}} into A(B('c'))" do
++        transform.apply({:a=>{:b=>'c'}}).should == A.new(B.new('c'))
++      end
++    end
++    describe "pulling out subbranches" do
++      before(:each) do
++        transform.rule(:a => {:b => simple(:x)}, :d => {:e => simple(:y)}) { |d|
++          Bi.new(*d.values_at(:x, :y))
++        }
++      end
++
++      it "should yield Bi.new('c', 'f')" do
++        transform.apply(:a => {:b => 'c'}, :d => {:e => 'f'}).should ==
++          Bi.new('c', 'f')
++      end 
++    end
++  end
++  describe "dsl construction" do
++    let(:transform) { Parslet::Transform.new do
++        rule(simple(:x)) { A.new(x) }
++      end 
++    }
++    
++    it "should still evaluate rules correctly" do
++      transform.apply('a').should == A.new('a')
++    end 
++  end
++  describe "class construction" do
++    class OptimusPrime < Parslet::Transform 
++      rule(simple(:x)) { A.new(x) }
++    end
++    let(:transform) { OptimusPrime.new }
++    
++    it "should evaluate rules" do
++      transform.apply('a').should == A.new('a')
++    end 
++  end
++  describe "<- #call_on_match" do
++    let(:bindings) { { :foo => 'test' } }
++    context "when given a block of arity 1" do
++      it "should call the block" do
++        called = false
++        transform.call_on_match(bindings, lambda do |dict|
++          called = true
++        end)
++        
++        called.should == true
++      end 
++      it "should yield the bindings" do
++        transform.call_on_match(bindings, lambda do |dict|
++          dict.should == bindings
++        end)
++      end
++      it "should execute in the current context"  do
++        foo = 'test'
++        transform.call_on_match(bindings, lambda do |dict|
++          foo.should == 'test'
++        end)
++      end
++    end
++    context "when given a block of arity 0" do
++      it "should call the block" do
++        called = false
++        transform.call_on_match(bindings, proc do 
++          called = true
++        end)
++        
++        called.should == true
++      end 
++      it "should have bindings as local variables" do
++        transform.call_on_match(bindings, proc do
++          foo.should == 'test'
++        end)
++      end
++      it "should execute in its own context" do
++        @bar = 'test'
++        transform.call_on_match(bindings, proc do
++          @bar.should_not == 'test'
++        end)
++      end
++    end
++  end
++  
++  context "various transformations (regression)" do
++    context "hashes" do
++      it "are matched completely" do
++        transform.rule(:a => simple(:x)) { fail }
++        transform.apply(:a => 'a', :b => 'b')
++      end 
++    end
++  end
++  
++  context "when not using the bindings as hash, but as local variables" do
++    it "should access the variables" do
++      transform.rule(simple(:x)) { A.new(x) }
++      transform.apply('a').should == A.new('a')
++    end
++    it "should allow context as local variable" do
++      transform.rule(simple(:x)) { foo }
++      transform.apply('a', :foo => 'bar').should == 'bar'
++    end
++  end
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/spec_helper.rb
+@@ -0,0 +1,24 @@
++
++require 'parslet'
++
++require 'parslet/rig/rspec'
++require 'parslet/atoms/visitor'
++require 'parslet/export'
++
++RSpec.configure do |config|
++  config.mock_with :flexmock
++  
++  # Exclude other ruby versions by giving :ruby => 1.8 or :ruby => 1.9
++  #
++  config.filter_run_excluding :ruby => lambda { |version|
++    RUBY_VERSION.to_s !~ /^#{Regexp.escape(version.to_s)}/
++  }
++end
++
++def catch_failed_parse
++  begin
++    yield
++  rescue Parslet::ParseFailed => exception
++  end
++  exception.cause
++end
+\ No newline at end of file
diff --git a/debian/patches/series b/debian/patches/series
index f9a853b..b4fa6cb 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1 +1 @@
-Drop-rubygems
+0001-Import-rspec-gemspec-from-upstream-Git-repo.patch
diff --git a/example/json.rb b/example/json.rb
index c72f32b..1ea1370 100644
--- a/example/json.rb
+++ b/example/json.rb
@@ -4,6 +4,7 @@ $:.unshift File.dirname(__FILE__) + "/../lib"
 # MIT License - (c) 2011 John Mettraux
 #
 
+require 'rubygems'
 require 'parslet' # gem install parslet
 
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ruby-extras/ruby-parslet.git



More information about the Pkg-ruby-extras-commits mailing list