[DRE-commits] [ruby-parslet] 02/03: Refresh patches

Youhei SASAKI uwabami-guest at moszumanska.debian.org
Wed Jul 23 11:32:36 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 4efae2b18541829160c8a53215e2ff4539e09dbb
Author: Youhei SASAKI <uwabami at gfd-dennou.org>
Date:   Wed Jul 23 20:22:21 2014 +0900

    Refresh patches
    
    Signed-off-by: Youhei SASAKI <uwabami at gfd-dennou.org>
---
 ...port-rspec-gemspec-from-upstream-Git-repo.patch | 926 ++++++++++++++++-----
 debian/patches/0002-Fix-Encoding.patch             |  20 -
 debian/patches/series                              |   1 -
 3 files changed, 702 insertions(+), 245 deletions(-)

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
index 4fa5110..892e79c 100644
--- a/debian/patches/0001-Import-rspec-gemspec-from-upstream-Git-repo.patch
+++ b/debian/patches/0001-Import-rspec-gemspec-from-upstream-Git-repo.patch
@@ -5,7 +5,13 @@ Subject: Import rspec, gemspec from upstream Git repo.
 Signed-off-by: Youhei SASAKI <uwabami at gfd-dennou.org>
 ---
  parslet.gemspec                              |  18 ++
+ qed/accelerators.md                          | 234 +++++++++++++++
+ qed/applique/ae.rb                           |   1 +
+ qed/applique/gobbleup.rb                     |  26 ++
+ qed/applique/parslet.rb                      |   4 +
+ qed/regressions.md                           |  60 ++++
  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 ++
@@ -13,12 +19,14 @@ Signed-off-by: Youhei SASAKI <uwabami at gfd-dennou.org>
  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      |  17 ++
+ 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 +
@@ -34,17 +42,24 @@ Signed-off-by: Youhei SASAKI <uwabami at gfd-dennou.org>
  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/position_spec.rb                |  10 +
+ spec/parslet/rig/rspec_spec.rb               |  54 ++++
  spec/parslet/scope_spec.rb                   |  45 +++
- spec/parslet/slice_spec.rb                   | 134 +++++++++
- spec/parslet/source/line_cache_spec.rb       |  39 +++
- spec/parslet/source_spec.rb                  | 154 ++++++++++
+ spec/parslet/slice_spec.rb                   | 140 +++++++++
+ spec/parslet/source/line_cache_spec.rb       |  74 +++++
+ spec/parslet/source_spec.rb                  | 168 +++++++++++
  spec/parslet/transform/context_spec.rb       |  35 +++
  spec/parslet/transform_spec.rb               | 144 +++++++++
- spec/spec_helper.rb                          |  24 ++
- 38 files changed, 2620 insertions(+)
+ spec/spec_helper.rb                          |  29 ++
+ 47 files changed, 3163 insertions(+)
  create mode 100644 parslet.gemspec
+ create mode 100644 qed/accelerators.md
+ create mode 100644 qed/applique/ae.rb
+ create mode 100644 qed/applique/gobbleup.rb
+ create mode 100644 qed/applique/parslet.rb
+ create mode 100644 qed/regressions.md
  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
@@ -55,9 +70,11 @@ Signed-off-by: Youhei SASAKI <uwabami at gfd-dennou.org>
  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
@@ -73,6 +90,7 @@ Signed-off-by: Youhei SASAKI <uwabami at gfd-dennou.org>
  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/position_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
@@ -82,17 +100,14 @@ Signed-off-by: Youhei SASAKI <uwabami at gfd-dennou.org>
  create mode 100644 spec/parslet/transform_spec.rb
  create mode 100644 spec/spec_helper.rb
 
-diff --git a/parslet.gemspec b/parslet.gemspec
-new file mode 100644
-index 0000000..793074f
 --- /dev/null
-+++ b/parslet.gemspec
++++ 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.version = '1.6.1'
 +
 +  s.authors = ['Kaspar Schiess']
 +  s.email = 'kaspar.schiess at absurd.li'
@@ -106,11 +121,351 @@ index 0000000..793074f
 +  
 +  s.add_dependency 'blankslate', '~> 2.0'
 +end
-diff --git a/spec/acceptance/examples_spec.rb b/spec/acceptance/examples_spec.rb
-new file mode 100644
-index 0000000..0fa7552
 --- /dev/null
-+++ b/spec/acceptance/examples_spec.rb
++++ ruby-parslet/qed/accelerators.md
+@@ -0,0 +1,234 @@
++# Parslet Accelerator
++
++## Synopsis
++
++Reading this all the way is worth it. But don't despair; if your attention span is short, read this and zap away! The TLDR:
++
++Parslet is slow because of the way it is constructed internally. Optimisation helps, but makes your parser harder to read. Don't go there. Use parser accelerators instead - optimize parts of your parser without changing its definition. This is what it looks like:
++
++    slow_parser = something >> slow_part >> other
++
++    include Parslet::Accelerator
++    optimized_parser = apply(
++      rule( slow_part ) { faster_part })
++
++    optimized_parser.parse('"Parsing is now fully optimized! (tm)"')
++
++Thus parslet allows you to write cristal clear parsers that are also as fast as you can make them. (But still slower than C!)
++
++## Introduction
++
++The goals of parslet are simple: make writing PEG parsers a predictable and straightforward endeavour. Some people have since claimed the word 'fun' for writing parsers, a connotation that we don't entirely oppose - otherwise why would we spend our time extending parslet?
++
++### Dark Clouds ahead
++
++Writing your first thousand line parser that works is easy – IF you use parslet. But very often, the resulting parser is rather slow - having execution times in the second range instead of the subsecond range.
++
++You fire up your email client and drop us a mail to the mailing list, asking: "Why is parslet so slow?" You'll receive the following answers:
++
++* Parslet is not a parser generator, but a parser engine based on Ruby. As such, it will be slower than parsers written in languages such as C.
++* Parslet's internal structure is simple and clear. We've invested a lot of effort in making everything it does obvious and extendable. The downside of this somewhat OO-heavy approach is that we've got many objects juggling data and deep callstacks. Read: Bad use of caches and CPU time.
++* Very few big languages have parsers written in high level languages such as Ruby. For good reasons. Depending on how serious you are about writing a new language (as opposed to fiddling around), you might want to _not start with parslet at all_.
++
++It's not like we haven't done anything to fix the above reasons; rather, we're doing everything we can, provided the main goal of *simplicity and understandability* is not in danger! If you look up what has been done over the years you will find a lot of small and large optimisations. But we have always refused to sacrifice simplicity of design to the god of optimisation, especially when it came to making a single parser faster. We want parslet to be fast in general, and frankly, your p [...]
++
++But parslet needs to be useful for something. If not, what is the point? We would like to make parslet as useful as possible for smaller languages and for places where execution speed isn't your only concern. A lot of languages have rapidly evolving grammars and are developed by programmers that don't have the time for hand-writing parsers in C.
++
++Still, what should you do once you've written your parser and speed becomes the issue? Until now, you had no real options short of rewriting the damn thing in C. That has changed: we've come up with Parslet Accelerator. The Accelerator will allow you to pattern match bits of your _parser_ and replace them with bits that do the same work, but faster. Really just hot spot optimisation, but without sacrificing readability of the original parser grammar.
++
++### An Example
++
++Let's consider the parser for quoted strings as an example, usually written to look something like this:
++
++    quote = str('"')
++    quote >> (quote.absent? >> any).repeat >> quote
++
++If we spell out the work parslet needs to do when matching a 1000 character string using this method, the performance problems will become obvious to you. Parslet will:
++
++* Match a quote
++* In a loop:
++  * Try to match a quote
++  * If that fails, continue, otherwise break from the loop
++  * Gobble up a single char
++* Match the final quote
++
++The inner loop will be executed a 1000 times; that's a 1000 times reading a char, checking to see if it's a quote, then reading it again, etc... As a programmer, this should disturb you deeply. And the fix, pseudo-code wise, should be obvious to you. Let's look at this revised flow:
++
++* Match a quote
++* Gobble up as many chars as possible, until we hit a quote
++* Match the final quote
++
++Ok, we've sort of cheated there in the middle - we've transformed something into a single step that is really still a loop. But as a Ruby programmer, you will not see this as a loop, but rather as a call to a more efficient library like `StringScanner`, which underlies `Parslet::Source`.
++
++So we're pretty confident that this new parser will work faster; maybe fast even. Let's assume that we've got a `GobbleUp` atom that gobbles up chars until it hits a stop char. Our faster parser would have to look something like this:
++
++    quote = str('"')
++    quote >> GobbleUp.new('"') >> quote
++
++And all is fine, right? We don't think so. You've chosen to use parslet, so you don't want to end up sprinkling your grammar which is as much specification as it is implementation with things like `GobbleUp`. Wouldn't it be nice if you could keep the parser as it is, but somehow replace the pattern of `(quote.absent? >> any).repeat` with `GobbleUp.new('"')` before doing any work with your parser? Well, you can.
++
++    quote = str('"')
++    parser = quote >> (quote.absent? >> any).repeat >> quote
++
++    A = Accelerator # for making what follows a bit shorter
++    optimized_parser = A.apply(parser,
++      A.rule( (A.str(:x).absent? >> A.any).repeat ) { GobbleUp.new(x) })
++
++    optimized_parser.parse('"Parsing is now fully optimized! (tm)"')
++
++(If you're interested in a bit of history, the example that triggered the discussion around accelerators is preserved in [optimizer.rb](https://github.com/kschiess/parslet/blob/master/experiments/optimizer.rb). If you look past the hacks and the optimism, you'll recognize some of the things we talk about in this document.)
++
++### About this Document
++
++Now that the goal is defined, let us expose the details of the system proposed above. We'll start with explaining what these `Accelerator.rule` things are, how they match against your parser and how binding of variables work. (*Parslet Pattern Matching*) Then we'll explain what actions you can take once you've matched part of your parser. (*Binding and Actions*)
++
++## Parser Pattern Matching
++
++We'll demonstrate how pattern detection is constructed by showing what the smallest parts do first. Let's require needed libraries.
++
++    require 'parslet'
++    require 'parslet/accelerator'
++
++    include Parslet
++
++The whole optimizer code is inside the `Parslet::Accelerator` module. If you read that, read 'particle accelerator', not 'will make my code fast'. It is very possible to make things worse using `Parslet::Accelerator`.
++
++The simplest parser I can think of would be the one matching a simple string.
++
++    atom = str('foo')
++    expression = Accelerator.str(:x)
++    binding = Accelerator.match(atom, expression)
++
++    binding[:x].assert == 'foo'
++
++Note that the above was somewhat verbose, with all these variables and all that. We'll write shorter examples from now on.
++
++Another simple parser is the one that matches against variants of the `match(...)` atom. Multiple forms of this exist, so we'll go through all of them. First comes a simple character range match.
++
++    binding = Accelerator.match(
++      match['a-z'],
++      Accelerator.re(:x))
++
++    binding[:x].assert == '[a-z]'
++
++Note how the internal regular expression value used for the match atom is really bound to :x – we'll keep this as a convention. This also means that some parslet internas are leaked through the Accelerator API here. We consider that a feature, since working with accelerators will bring you into close contact with the atoms internas.
++
++Also the Accelerator matcher for `Parslet.match` is called `Accelerator.re` - the reason for this should be obvious from what stands above.
++
++Just to make this complete, a special case for the `match(...)` atom is the `any` atom.
++
++    binding = Accelerator.match(any, Accelerator.any)
++    binding.assert != nil
++
++## Composite Parsers
++
++Let's start assembling these simple parsers into more complex patterns and match those. As our first pattern, we'll consider sequences.
++
++    binding = Accelerator.match(
++      str('a') >> str('b'),
++      Accelerator.str(:x) >> Accelerator.str(:y))
++
++    binding.values_at(:x, :y).assert == %w(a b)
++
++Also, alternatives should correctly bind.
++
++    binding = Accelerator.match(
++      str('a') | str('b'),
++      Accelerator.str(:x) | Accelerator.str(:y))
++
++    binding.values_at(:x, :y).assert == %w(a b)
++
++Note that this means that we bind to the whole alternative subtree, not either to the left or to the right. We're matching the parslet tree, so the meaning of the alternative is irrelevant.
++
++Let's quickly skip through the list of other composite parsers here: First off is repetition.
++
++    Accelerator.match(
++      str('a').repeat(1,2),
++      A.str('a').repeat(1,2)).assert != nil
++
++And then there is positive and negative lookahead.
++
++    Accelerator.match(
++      str('a').present?,
++      A.str('a').present?).assert != nil
++
++    Accelerator.match(
++      str('a').absent?,
++      A.str('a').absent?).assert != nil
++
++And named values.
++
++    Accelerator.match(
++      str('a').as(:a),
++      A.str('a').as(:a)).assert != nil
++
++Which we also want to be able to bind.
++
++    Accelerator.match(
++      str('a').as(:a),
++      A.str('a').as(:b)).assert == {:b => :a}
++
++## Binding to Values
++
++As a side note, our parser should also respect literal value matches in the pattern and only bind to subsequent locations when the values match up.
++
++    binding = Accelerator.match(
++      str('a') >> str('b'),
++      Accelerator.str(:x) >> Accelerator.str(:x))
++
++    binding.assert == nil
++
++Another property should be that literal strings passed to the pattern should be matched using ===.
++
++    binding = Accelerator.match(
++      str('abc') >> str('bcd'),
++      Accelerator.str(/b/) >> Accelerator.str('bcd'))
++
++    binding.assert == {}
++
++The binding is empty here, since no variables were given. But lets also implement constrained variable bindings, that seems useful. The way this works is that you specify a variable you want to bind to first, and then a list of constraints that are matched by `#===`.
++
++    A.match(str('abc'), A.str(:x, /c/))[:x].assert == 'abc'
++    A.match(str('abc'), A.str(:x, /d/)).assert == nil
++
++    A.match(str('abc'), A.str(:x, /a/, /c/))[:x].assert == 'abc'
++    A.match(str('abc'), A.str(:x, /a/, /d/)).assert == nil
++
++Here's a quick demonstration that demonstrates that this feature equally applies to both `Accelerator.re` and `Parslet.match`.
++
++    A.match(match['abc'], A.re(:x, /d/)).assert == nil
++    A.match(match['abc'], A.re(:x, /c/))[:x].assert == '[abc]'
++
++## Bindings and Actions
++
++Matching parsers is only useful if we can take action and create a new parser that is different in some way. Let's say we have the lofty goal of creating an 'accelerator' that reverses the language understood by a parser. Where the first parser would parse something like:
++
++    aaaaabbbb
++
++we want the second parser to parse something like:
++
++    bbbaaaaa
++
++Here's how the first parser would look like:
++
++    parser = str('a').repeat(1) >> str('b').repeat(1)
++
++And here's how we turn this around to parse the second kind of input.
++
++    include Parslet
++    parser = str('a').repeat(1) >> str('b').repeat(1)
++    new_parser = A.apply(parser,
++      A.rule(A.str(:x).repeat(1) >> A.str(:y).repeat(1)) { 
++        str(y).repeat(1) >> str(x).repeat(1) } )
++
++    new_parser.parse('bbbaaaa').assert == 'bbbaaaa'
++
++The `Accelerator.apply` method should be called with the following schema: 
++
++    Accelerator.apply(PARSER, RULE1, RULE2, ...)
++
++This is a more modern syntax than `Parslet::Transform` uses - maybe we'll update that class in a future version.
++
++## Closing Note
++
++* not a panacea
+--- /dev/null
++++ ruby-parslet/qed/applique/ae.rb
+@@ -0,0 +1 @@
++require 'ae'
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/qed/applique/gobbleup.rb
+@@ -0,0 +1,26 @@
++
++require 'parslet'
++
++# This is where the famous GobbleUp atom is defined. This parslet atom consumes
++# all chars until a given string (absent) is encountered.
++#
++class GobbleUp < Parslet::Atoms::Base
++  def initialize absent, min_chars=0
++    @absent = absent
++    @min_chars = min_chars
++  end
++
++  def try(source, context, consume_all)
++    excluding_length = source.chars_until(@absent)
++
++    if excluding_length >= @min_chars
++      return succ(source.consume(excluding_length))
++    else
++      return context.err(self, source, "No such string in input: #{@absent.inspect}.")
++    end
++  end
++
++  def to_s_inner(prec)
++    "until('#{@absent}')"
++  end
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/qed/applique/parslet.rb
+@@ -0,0 +1,4 @@
++require 'parslet'
++require 'parslet/accelerator'
++
++include Parslet
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/qed/regressions.md
+@@ -0,0 +1,60 @@
++
++# Intro
++
++This document collects all sorts of weird bugs that parslet had over the years and asserts that we don't accidentially reintroduce one of these. There's not much to be learnt here but a few war stories to be had. 
++
++# Regresssions
++
++## Redefinition of Ruby core methods
++
++This [bug](https://github.com/kschiess/parslet/issues/101) came up at least twice. When constructing a parser like this
++
++    class HashParser < Parslet::Parser
++      rule(:str_hash) { str('hash') }
++      rule(:hash) { str_hash }
++      rule(:expr) { hash }
++      root(:expr)
++    end
++
++We're essentially redefining the parser object's #hash method here. So the parse might work, but the packrat caching doesn't - because it used to stick parsers into a hash. Now this should be impossible, because we're using the `#object_id` of the parser - a speed gain
++
++    HashParser.new.parse('hash') # did raise a TypeError, but doesn't now
++
++Looking back, getting this error was not only probable, but inevitable: Everyone constructs parsers for programming languages, and almost all modern programming languages know the hash as a construct. Hope this one stays buried. 
++
++## i18n and the Difference between Byte and Character Position
++
++This is hard to get right, especially when considering the differences between the 1.8 and 1.9 branches of Ruby. By dropping 1.8 support, we got rid of a special branch of problems, now really the only thing that remains is treating character and byte offsets consistently. Ruby itself doesn't really: 
++
++| method                  | seeks by/returns  |
++-----------------------------------------------
++| `String#[]`             | character         |
++| `StringScanner#pos`     | byte              |
++| `StringScanner#pos=`    | byte              |
++| `StringScanner#charpos` | character         |
++
++In parslet, we adopt the following conventions: 
++
++* `Source#bytepos` and `Source#bytepos=` only deal in byte positions. We don't have a choice here, since StringScanner only seeks to byte locations, probably for speed reasons. These methods are used internally for parsing, caching and resetting the parse. 
++* `Source#pos` returns character positions. This method is used for returning positions associated to slices. 
++
++So let's test if we get this right by using input composed of the unicode chars 'öäü', mainly because I can type those easily on this keyboard. 
++
++    class I18NParser < Parslet::Parser
++      rule(:nl) { str("\n") }
++      rule(:ouml) { str("ö") }
++      rule(:auml) { str("ä") }
++      rule(:expr) { ((ouml | auml).repeat(1).as(:line) >> nl).repeat(1) }
++      root(:expr)
++    end
++
++    result = I18NParser.new.parse("äö\nä\nö\n")
++
++    [{ofs: 0, line: 1, col: 1}, 
++     {ofs: 3, line: 2, col: 1}, 
++     {ofs: 5, line: 3, col: 1}].zip(result).each do |expect, capture|
++      capture[:line].offset.assert == expect[:ofs]
++      capture[:line].line_and_column.assert == expect.values_at(:line, :col)
++    end 
++
++
+--- /dev/null
++++ ruby-parslet/spec/acceptance/examples_spec.rb
 @@ -0,0 +1,37 @@
 +require 'spec_helper'
 +require 'open3'
@@ -125,8 +480,8 @@ index 0000000..0fa7552
 +          gsub('example/','example/output/')
 +      end
 +      
-+      it "runs successfully", :ruby => 1.9 do
-+        stdin, stdout, stderr = Open3.popen3("ruby #{example}")
++      it "runs successfully" do
++        stdin, stdout, stderr = Open3.popen3("ruby -Ku #{example}")
 +        
 +        handle_map = {
 +          stdout => :out, 
@@ -149,11 +504,124 @@ index 0000000..0fa7552
 +    end
 +  end
 +end
-diff --git a/spec/acceptance/regression_spec.rb b/spec/acceptance/regression_spec.rb
-new file mode 100644
-index 0000000..0135d94
 --- /dev/null
-+++ b/spec/acceptance/regression_spec.rb
++++ ruby-parslet/spec/acceptance/infix_parser_spec.rb
+@@ -0,0 +1,112 @@
++require 'spec_helper'
++
++describe 'Infix expression parsing' do
++  class InfixExpressionParser < Parslet::Parser
++    rule(:space) { match['\s'] }
++
++    def cts atom
++      atom >> space.repeat
++    end
++    def infix *args
++      Infix.new(*args)
++    end
++
++    rule(:mul_op) { match['*/'] >> str(' ').maybe }
++    rule(:add_op) { match['+-'] >> str(' ').maybe }
++    rule(:digit) { match['0-9'] }
++    rule(:integer) { cts digit.repeat(1) }
++
++    rule(:expression) { infix_expression(integer, 
++      [mul_op, 2, :left], 
++      [add_op, 1, :right]) }
++  end
++
++  let(:p) { InfixExpressionParser.new }
++  describe '#integer' do
++    let(:i) { p.integer }
++    it "parses integers" do
++      i.should parse('1')
++      i.should parse('123')
++    end 
++    it "consumes trailing white space" do
++      i.should parse('1   ')
++      i.should parse('134   ')
++    end 
++    it "doesn't parse floats" do
++      i.should_not parse('1.3')
++    end 
++  end
++  describe '#multiplication' do
++    let(:m) { p.expression }
++    it "parses simple multiplication" do
++      m.should parse('1*2').as(l: '1', o: '*', r: '2')
++    end
++    it "parses simple multiplication with spaces" do
++      m.should parse('1 * 2').as(l: '1 ', o: '* ', r: '2')
++    end
++    it "parses division" do
++      m.should parse('1/2')
++    end 
++  end
++  describe '#addition' do
++    let(:a) { p.expression }
++    
++    it "parses simple addition" do
++      a.should parse('1+2')
++    end 
++    it "parses complex addition" do
++      a.should parse('1+2+3-4')
++    end
++    it "parses a single element" do
++      a.should parse('1')
++    end
++  end
++
++  describe 'mixed operations' do
++    let(:mo) { p.expression }
++
++    describe 'inspection' do
++      it 'produces useful expressions' do
++        p.expression.parslet.inspect.should == 
++          "infix_expression(INTEGER, [MUL_OP, ADD_OP])"
++      end
++    end
++    describe 'right associativity' do
++      it 'produces trees that lean right' do
++        mo.should parse('1+2+3').as(
++          l: '1', o: '+', r: {l: '2', o: '+', r: '3'})
++      end      
++    end
++    describe 'left associativity' do
++      it 'produces trees that lean left' do
++        mo.should parse('1*2*3').as(
++          l: {l:'1', o:'*', r:'2'}, o:'*', r:'3')
++      end      
++    end
++    describe 'error handling' do
++      describe 'incomplete expression' do
++        it 'produces the right error' do
++          cause = catch_failed_parse {
++            mo.parse('1+') }
++
++          cause.ascii_tree.to_s.should == <<-ERROR
++INTEGER was expected at line 1 char 3.
++`- Failed to match sequence (DIGIT{1, } SPACE{0, }) at line 1 char 3.
++   `- Expected at least 1 of DIGIT at line 1 char 3.
++      `- Premature end of input at line 1 char 3.
++          ERROR
++        end
++      end
++      describe 'invalid operator' do
++        it 'produces the right error' do
++          cause = catch_failed_parse {
++            mo.parse('1%') }
++
++          cause.ascii_tree.to_s.should == <<-ERROR
++Don't know what to do with "%" at line 1 char 2.
++          ERROR
++        end
++      end
++    end
++  end
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/acceptance/regression_spec.rb
 @@ -0,0 +1,314 @@
 +# Encoding: UTF-8
 +
@@ -244,7 +712,7 @@ index 0000000..0135d94
 +        lambda {
 +          instance.parse('((()))')
 +          instance.parse('(((())))')
-+        }.should_not raise_error(Parslet::ParseFailed)
++        }.should_not raise_error
 +      end 
 +    end
 +    context "expression '(())'" do
@@ -341,7 +809,7 @@ index 0000000..0135d94
 +    rule(:sentences) { sentence.repeat }
 +    root(:sentences)
 +  end
-+  describe UnicodeSentenceLanguage, :ruby => 1.9 do
++  describe UnicodeSentenceLanguage do
 +    let(:string) {
 +      "RubyKaigi2009のテーマは、「変わる/変える」です。 前回の" +
 +      "RubyKaigi2008のテーマであった「多様性」の言葉の通り、 " +
@@ -469,12 +937,8 @@ index 0000000..0135d94
 +    end
 +  end
 +end
-\ No newline at end of file
-diff --git a/spec/acceptance/repetition_and_maybe_spec.rb b/spec/acceptance/repetition_and_maybe_spec.rb
-new file mode 100644
-index 0000000..8bfcab5
 --- /dev/null
-+++ b/spec/acceptance/repetition_and_maybe_spec.rb
++++ ruby-parslet/spec/acceptance/repetition_and_maybe_spec.rb
 @@ -0,0 +1,42 @@
 +require 'spec_helper'
 +
@@ -519,11 +983,8 @@ index 0000000..8bfcab5
 +  end
 +end
 \ No newline at end of file
-diff --git a/spec/acceptance/unconsumed_input_spec.rb b/spec/acceptance/unconsumed_input_spec.rb
-new file mode 100644
-index 0000000..ffc48f8
 --- /dev/null
-+++ b/spec/acceptance/unconsumed_input_spec.rb
++++ ruby-parslet/spec/acceptance/unconsumed_input_spec.rb
 @@ -0,0 +1,21 @@
 +require 'spec_helper'
 +
@@ -547,11 +1008,8 @@ index 0000000..ffc48f8
 +  end
 +end
 \ No newline at end of file
-diff --git a/spec/parslet/atom_results_spec.rb b/spec/parslet/atom_results_spec.rb
-new file mode 100644
-index 0000000..1dcfafa
 --- /dev/null
-+++ b/spec/parslet/atom_results_spec.rb
++++ ruby-parslet/spec/parslet/atom_results_spec.rb
 @@ -0,0 +1,39 @@
 +require 'spec_helper'
 +
@@ -593,11 +1051,8 @@ index 0000000..1dcfafa
 +  end
 +end
 \ No newline at end of file
-diff --git a/spec/parslet/atoms/alternative_spec.rb b/spec/parslet/atoms/alternative_spec.rb
-new file mode 100644
-index 0000000..79bd296
 --- /dev/null
-+++ b/spec/parslet/atoms/alternative_spec.rb
++++ ruby-parslet/spec/parslet/atoms/alternative_spec.rb
 @@ -0,0 +1,26 @@
 +require 'spec_helper'
 +
@@ -626,11 +1081,8 @@ index 0000000..79bd296
 +  end
 +end
 \ No newline at end of file
-diff --git a/spec/parslet/atoms/base_spec.rb b/spec/parslet/atoms/base_spec.rb
-new file mode 100644
-index 0000000..d94bd81
 --- /dev/null
-+++ b/spec/parslet/atoms/base_spec.rb
++++ ruby-parslet/spec/parslet/atoms/base_spec.rb
 @@ -0,0 +1,124 @@
 +require 'spec_helper'
 +
@@ -688,7 +1140,7 @@ index 0000000..d94bd81
 +    context "when given something that looks like a source" do
 +      let(:source) { flexmock("source lookalike", 
 +        :line_and_column => [1,2], 
-+        :pos => 1, 
++        :bytepos => 1, 
 +        :chars_left => 0) }
 +      
 +      it "should not rewrap in a source" do
@@ -757,11 +1209,8 @@ index 0000000..d94bd81
 +  end
 +end
 \ No newline at end of file
-diff --git a/spec/parslet/atoms/capture_spec.rb b/spec/parslet/atoms/capture_spec.rb
-new file mode 100644
-index 0000000..2f3a68a
 --- /dev/null
-+++ b/spec/parslet/atoms/capture_spec.rb
++++ ruby-parslet/spec/parslet/atoms/capture_spec.rb
 @@ -0,0 +1,21 @@
 +require 'spec_helper'
 +
@@ -785,35 +1234,17 @@ index 0000000..2f3a68a
 +  end 
 +end
 \ No newline at end of file
-diff --git a/spec/parslet/atoms/combinations_spec.rb b/spec/parslet/atoms/combinations_spec.rb
-new file mode 100644
-index 0000000..4ea7d44
 --- /dev/null
-+++ b/spec/parslet/atoms/combinations_spec.rb
-@@ -0,0 +1,17 @@
++++ ruby-parslet/spec/parslet/atoms/combinations_spec.rb
+@@ -0,0 +1,5 @@
 +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
-diff --git a/spec/parslet/atoms/dsl_spec.rb b/spec/parslet/atoms/dsl_spec.rb
-new file mode 100644
-index 0000000..8eee35a
 --- /dev/null
-+++ b/spec/parslet/atoms/dsl_spec.rb
++++ ruby-parslet/spec/parslet/atoms/dsl_spec.rb
 @@ -0,0 +1,17 @@
 +require 'spec_helper'
 +
@@ -833,11 +1264,8 @@ index 0000000..8eee35a
 +  end
 +end
 \ No newline at end of file
-diff --git a/spec/parslet/atoms/entity_spec.rb b/spec/parslet/atoms/entity_spec.rb
-new file mode 100644
-index 0000000..a5499bc
 --- /dev/null
-+++ b/spec/parslet/atoms/entity_spec.rb
++++ ruby-parslet/spec/parslet/atoms/entity_spec.rb
 @@ -0,0 +1,52 @@
 +require 'spec_helper'
 +
@@ -892,11 +1320,17 @@ index 0000000..a5499bc
 +  end
 +end
 \ No newline at end of file
-diff --git a/spec/parslet/atoms/lookahead_spec.rb b/spec/parslet/atoms/lookahead_spec.rb
-new file mode 100644
-index 0000000..ac54ecd
 --- /dev/null
-+++ b/spec/parslet/atoms/lookahead_spec.rb
++++ ruby-parslet/spec/parslet/atoms/infix_spec.rb
+@@ -0,0 +1,5 @@
++require 'spec_helper'
++
++describe Parslet::Atoms::Infix do
++
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/parslet/atoms/lookahead_spec.rb
 @@ -0,0 +1,22 @@
 +require 'spec_helper'
 +
@@ -921,22 +1355,16 @@ index 0000000..ac54ecd
 +  end
 +end
 \ No newline at end of file
-diff --git a/spec/parslet/atoms/named_spec.rb b/spec/parslet/atoms/named_spec.rb
-new file mode 100644
-index 0000000..98ce14d
 --- /dev/null
-+++ b/spec/parslet/atoms/named_spec.rb
++++ 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
-diff --git a/spec/parslet/atoms/re_spec.rb b/spec/parslet/atoms/re_spec.rb
-new file mode 100644
-index 0000000..44f9cd7
 --- /dev/null
-+++ b/spec/parslet/atoms/re_spec.rb
++++ ruby-parslet/spec/parslet/atoms/re_spec.rb
 @@ -0,0 +1,14 @@
 +require 'spec_helper'
 +
@@ -953,11 +1381,36 @@ index 0000000..44f9cd7
 +  end
 +end
 \ No newline at end of file
-diff --git a/spec/parslet/atoms/scope_spec.rb b/spec/parslet/atoms/scope_spec.rb
-new file mode 100644
-index 0000000..2664bc8
 --- /dev/null
-+++ b/spec/parslet/atoms/scope_spec.rb
++++ ruby-parslet/spec/parslet/atoms/repetition_spec.rb
+@@ -0,0 +1,24 @@
++require 'spec_helper'
++
++describe Parslet::Atoms::Repetition 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
++    describe "0 times" do
++      it "raises an ArgumentError" do
++        expect {
++          parslet.repeat(0,0)
++        }.to raise_error(ArgumentError)
++      end
++    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'
 +
@@ -986,11 +1439,8 @@ index 0000000..2664bc8
 +  end 
 +end
 \ No newline at end of file
-diff --git a/spec/parslet/atoms/sequence_spec.rb b/spec/parslet/atoms/sequence_spec.rb
-new file mode 100644
-index 0000000..c2cec13
 --- /dev/null
-+++ b/spec/parslet/atoms/sequence_spec.rb
++++ ruby-parslet/spec/parslet/atoms/sequence_spec.rb
 @@ -0,0 +1,28 @@
 +require 'spec_helper'
 +
@@ -1020,11 +1470,8 @@ index 0000000..c2cec13
 +    
 +  end
 +end
-diff --git a/spec/parslet/atoms/str_spec.rb b/spec/parslet/atoms/str_spec.rb
-new file mode 100644
-index 0000000..455f82d
 --- /dev/null
-+++ b/spec/parslet/atoms/str_spec.rb
++++ ruby-parslet/spec/parslet/atoms/str_spec.rb
 @@ -0,0 +1,15 @@
 +# Encoding: UTF-8
 +
@@ -1042,11 +1489,8 @@ index 0000000..455f82d
 +  end
 +end
 \ No newline at end of file
-diff --git a/spec/parslet/atoms/visitor_spec.rb b/spec/parslet/atoms/visitor_spec.rb
-new file mode 100644
-index 0000000..c195cee
 --- /dev/null
-+++ b/spec/parslet/atoms/visitor_spec.rb
++++ ruby-parslet/spec/parslet/atoms/visitor_spec.rb
 @@ -0,0 +1,80 @@
 +require 'spec_helper'
 +
@@ -1129,11 +1573,8 @@ index 0000000..c195cee
 +  end
 +end
 \ No newline at end of file
-diff --git a/spec/parslet/atoms_spec.rb b/spec/parslet/atoms_spec.rb
-new file mode 100644
-index 0000000..cd247ba
 --- /dev/null
-+++ b/spec/parslet/atoms_spec.rb
++++ ruby-parslet/spec/parslet/atoms_spec.rb
 @@ -0,0 +1,429 @@
 +require 'spec_helper'
 +
@@ -1226,7 +1667,7 @@ index 0000000..cd247ba
 +    it "should leave pos untouched if there is no foo" do
 +      source = src('bar')
 +      parslet.apply(source, context)
-+      source.pos.should == 0
++      source.pos.charpos.should == 0
 +    end
 +    it "should inspect as 'foo'?" do
 +      parslet.inspect.should == "'foo'?"
@@ -1310,7 +1751,7 @@ index 0000000..cd247ba
 +      it "should not change input position" do
 +        source = src('foo')
 +        parslet.apply(source, context)
-+        source.pos.should == 0
++        source.pos.charpos.should == 0
 +      end
 +    end
 +    context "when fed 'bar'" do
@@ -1340,7 +1781,7 @@ index 0000000..cd247ba
 +      it "should not change input position" do
 +        source = src('bar')
 +        parslet.apply(source, context)
-+        source.pos.should == 0
++        source.pos.charpos.should == 0
 +      end
 +    end
 +    context "when fed 'foo'" do
@@ -1378,7 +1819,7 @@ index 0000000..cd247ba
 +    it "should consume one char" do
 +      source = src('foo')
 +      parslet.apply(source, context)
-+      source.pos.should == 1
++      source.pos.charpos.should == 1
 +    end 
 +  end
 +  describe "eof behaviour" do
@@ -1535,7 +1976,7 @@ index 0000000..cd247ba
 +  end
 +
 +  describe "combinations thereof (regression)" do
-+    sucess =[
++    success=[
 +      [(str('a').repeat >> str('b').repeat), 'aaabbb'] 
 +    ].each do |(parslet, input)|
 +      describe "#{parslet.inspect} applied to #{input.inspect}" do
@@ -1565,11 +2006,8 @@ index 0000000..cd247ba
 +  end
 +end
 \ No newline at end of file
-diff --git a/spec/parslet/convenience_spec.rb b/spec/parslet/convenience_spec.rb
-new file mode 100644
-index 0000000..5a62b83
 --- /dev/null
-+++ b/spec/parslet/convenience_spec.rb
++++ ruby-parslet/spec/parslet/convenience_spec.rb
 @@ -0,0 +1,48 @@
 +require 'spec_helper'
 +
@@ -1591,10 +2029,10 @@ index 0000000..5a62b83
 +        parser.should_receive(:puts)
 +      end
 +      it 'should exist' do
-+        lambda { parser.parse_with_debug('anything') }.should_not raise_error(NoMethodError)
++        lambda { parser.parse_with_debug('anything') }.should_not raise_error
 +      end
 +      it 'should catch ParseFailed exceptions' do
-+        lambda { parser.parse_with_debug('bar') }.should_not raise_error(Parslet::ParseFailed)
++        lambda { parser.parse_with_debug('bar') }.should_not raise_error
 +      end
 +      it 'should parse correct input like #parse' do
 +        lambda { parser.parse_with_debug('foo') }.should_not raise_error
@@ -1619,12 +2057,8 @@ index 0000000..5a62b83
 +    end 
 +  end
 +end
-\ No newline at end of file
-diff --git a/spec/parslet/error_reporter/deepest_spec.rb b/spec/parslet/error_reporter/deepest_spec.rb
-new file mode 100644
-index 0000000..e3000f0
 --- /dev/null
-+++ b/spec/parslet/error_reporter/deepest_spec.rb
++++ ruby-parslet/spec/parslet/error_reporter/deepest_spec.rb
 @@ -0,0 +1,73 @@
 +require 'spec_helper'
 +
@@ -1700,11 +2134,8 @@ index 0000000..e3000f0
 +  end
 +end
 \ No newline at end of file
-diff --git a/spec/parslet/error_reporter/tree_spec.rb b/spec/parslet/error_reporter/tree_spec.rb
-new file mode 100644
-index 0000000..a8b08ab
 --- /dev/null
-+++ b/spec/parslet/error_reporter/tree_spec.rb
++++ ruby-parslet/spec/parslet/error_reporter/tree_spec.rb
 @@ -0,0 +1,7 @@
 +require 'spec_helper'
 +
@@ -1714,11 +2145,8 @@ index 0000000..a8b08ab
 +  
 +end
 \ No newline at end of file
-diff --git a/spec/parslet/export_spec.rb b/spec/parslet/export_spec.rb
-new file mode 100644
-index 0000000..8f12152
 --- /dev/null
-+++ b/spec/parslet/export_spec.rb
++++ ruby-parslet/spec/parslet/export_spec.rb
 @@ -0,0 +1,67 @@
 +require 'spec_helper'
 +
@@ -1788,11 +2216,8 @@ index 0000000..8f12152
 +  end
 +end
 \ No newline at end of file
-diff --git a/spec/parslet/expression/treetop_spec.rb b/spec/parslet/expression/treetop_spec.rb
-new file mode 100644
-index 0000000..0c0340f
 --- /dev/null
-+++ b/spec/parslet/expression/treetop_spec.rb
++++ ruby-parslet/spec/parslet/expression/treetop_spec.rb
 @@ -0,0 +1,74 @@
 +require 'spec_helper'
 +
@@ -1869,11 +2294,8 @@ index 0000000..0c0340f
 +  end
 +end
 \ No newline at end of file
-diff --git a/spec/parslet/minilisp.citrus b/spec/parslet/minilisp.citrus
-new file mode 100644
-index 0000000..fea3d2e
 --- /dev/null
-+++ b/spec/parslet/minilisp.citrus
++++ ruby-parslet/spec/parslet/minilisp.citrus
 @@ -0,0 +1,29 @@
 +grammar MiniLisp
 +  rule root
@@ -1904,11 +2326,8 @@ index 0000000..fea3d2e
 +    ("\"" (("\\" .) | (!"\"" .))0* "\"" (space_p))
 +  end
 +end
-diff --git a/spec/parslet/minilisp.tt b/spec/parslet/minilisp.tt
-new file mode 100644
-index 0000000..e0ada6d
 --- /dev/null
-+++ b/spec/parslet/minilisp.tt
++++ ruby-parslet/spec/parslet/minilisp.tt
 @@ -0,0 +1,29 @@
 +grammar MiniLisp
 +  rule root
@@ -1939,11 +2358,8 @@ index 0000000..e0ada6d
 +    ("\"" (("\\" .) / (!"\"" .))0.. "\"" (space_p))
 +  end
 +end
-diff --git a/spec/parslet/parser_spec.rb b/spec/parslet/parser_spec.rb
-new file mode 100644
-index 0000000..c7e67b8
 --- /dev/null
-+++ b/spec/parslet/parser_spec.rb
++++ ruby-parslet/spec/parslet/parser_spec.rb
 @@ -0,0 +1,31 @@
 +require 'spec_helper'
 +
@@ -1977,11 +2393,8 @@ index 0000000..c7e67b8
 +  end
 +end
 \ No newline at end of file
-diff --git a/spec/parslet/parslet_spec.rb b/spec/parslet/parslet_spec.rb
-new file mode 100644
-index 0000000..aea9ec4
 --- /dev/null
-+++ b/spec/parslet/parslet_spec.rb
++++ ruby-parslet/spec/parslet/parslet_spec.rb
 @@ -0,0 +1,38 @@
 +require 'spec_helper'
 +
@@ -2022,11 +2435,8 @@ index 0000000..aea9ec4
 +  end
 +end
 \ No newline at end of file
-diff --git a/spec/parslet/pattern_spec.rb b/spec/parslet/pattern_spec.rb
-new file mode 100644
-index 0000000..2b4756f
 --- /dev/null
-+++ b/spec/parslet/pattern_spec.rb
++++ ruby-parslet/spec/parslet/pattern_spec.rb
 @@ -0,0 +1,268 @@
 +require 'spec_helper'
 +
@@ -2297,12 +2707,23 @@ index 0000000..2b4756f
 +  end
 +end
 \ No newline at end of file
-diff --git a/spec/parslet/rig/rspec_spec.rb b/spec/parslet/rig/rspec_spec.rb
-new file mode 100644
-index 0000000..3e78449
 --- /dev/null
-+++ b/spec/parslet/rig/rspec_spec.rb
-@@ -0,0 +1,35 @@
++++ ruby-parslet/spec/parslet/position_spec.rb
+@@ -0,0 +1,10 @@
++# Encoding: UTF-8
++
++require 'spec_helper'
++
++describe Parslet::Position do
++  slet(:position) { described_class.new('öäüö', 4) }
++
++  its(:charpos) { should == 2 }
++  its(:bytepos) { should == 4 } 
++end
+\ No newline at end of file
+--- /dev/null
++++ ruby-parslet/spec/parslet/rig/rspec_spec.rb
+@@ -0,0 +1,54 @@
 +require 'spec_helper'
 +require 'parslet/rig/rspec'
 +
@@ -2338,11 +2759,27 @@ index 0000000..3e78449
 +  # end
 +  
 +end
-diff --git a/spec/parslet/scope_spec.rb b/spec/parslet/scope_spec.rb
-new file mode 100644
-index 0000000..398c3be
++
++describe 'rspec3 syntax' do
++  include Parslet
++
++  let(:s) { str('example') }
++
++  it { expect(s).to parse('example') }
++  it { expect(s).not_to parse('foo') }
++  it { expect(s).to parse('example').as('example') }
++  it { expect(s).not_to parse('foo').as('example') }
++
++  it { expect(s).not_to parse('example').as('foo') }
++
++  # Uncomment to test error messages manually: 
++  # it { expect(str('foo')).to parse('foo', :trace => true).as('bar') }
++  # it { expect(str('foo')).to parse('food', :trace => true) }
++  # it { expect(str('foo')).not_to parse('foo', :trace => true).as('foo') }
++  # it { expect(str('foo')).not_to parse('foo', :trace => true) }
++end
 --- /dev/null
-+++ b/spec/parslet/scope_spec.rb
++++ ruby-parslet/spec/parslet/scope_spec.rb
 @@ -0,0 +1,45 @@
 +require 'spec_helper'
 +
@@ -2390,30 +2827,33 @@ index 0000000..398c3be
 +  end
 +end
 \ No newline at end of file
-diff --git a/spec/parslet/slice_spec.rb b/spec/parslet/slice_spec.rb
-new file mode 100644
-index 0000000..ef41d35
 --- /dev/null
-+++ b/spec/parslet/slice_spec.rb
-@@ -0,0 +1,134 @@
++++ ruby-parslet/spec/parslet/slice_spec.rb
+@@ -0,0 +1,140 @@
 +require 'spec_helper'
 +
 +describe Parslet::Slice do
++  def cslice string, offset, cache=nil
++    described_class.new(
++      Parslet::Position.new(string, offset), 
++      string, cache)
++  end
++
 +  describe "construction" do
 +    it "should construct from an offset and a string" do
-+      described_class.new('foobar', 40)
++      cslice('foobar', 40)
 +    end
 +  end
-+  context "('foobar', 40)" do
-+    let(:slice) { described_class.new('foobar', 40) }
++  context "('foobar', 40, 'foobar')" do
++    let(:slice) { cslice('foobar', 40) }
 +    describe "comparison" do
 +      it "should be equal to other slices with the same attributes" do
-+        other = described_class.new('foobar', 40)
++        other = cslice('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)
++        other = cslice('foobar', 41)
 +        slice.should == other
 +        other.should == slice
 +      end 
@@ -2435,7 +2875,7 @@ index 0000000..ef41d35
 +    end
 +    describe "offset" do
 +      it "should return the associated offset" do
-+        slice.offset.should == 40
++        slice.offset.should == 6
 +      end
 +      it "should fail to return a line and column" do
 +        lambda {
@@ -2444,7 +2884,7 @@ index 0000000..ef41d35
 +      end 
 +      
 +      context "when constructed with a source" do
-+        let(:slice) { described_class.new(
++        let(:slice) { cslice(
 +          'foobar', 40,  
 +          flexmock(:cache, :line_and_column => [13, 14])) }
 +        it "should return proper line and column" do
@@ -2467,13 +2907,13 @@ index 0000000..ef41d35
 +        it { should == 6 } 
 +      end
 +      describe "<- #+" do
-+        let(:other) { described_class.new('baz', 10) }
++        let(:other) { cslice('baz', 10) }
 +        subject { slice + other }
 +        
 +        it "should concat like string does" do
 +          subject.size.should == 9
 +          subject.should == 'foobarbaz'
-+          subject.offset.should == 40
++          subject.offset.should == 6
 +        end 
 +      end
 +    end
@@ -2490,12 +2930,12 @@ index 0000000..ef41d35
 +      end
 +      describe "cast to Float" do
 +        it "should return a float" do
-+          Float(described_class.new('1.345', 11)).should == 1.345
++          Float(cslice('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)
++          s = cslice('1234', 40)
 +          Integer(s).should == 1234
 +          s.to_i.should == 1234
 +        end 
@@ -2510,7 +2950,7 @@ index 0000000..ef41d35
 +    describe "inspection and string conversion" do
 +      describe "#inspect" do
 +        subject { slice.inspect }
-+        it { should == '"foobar"@40' }
++        it { should == '"foobar"@6' }
 +      end
 +      describe "#to_s" do
 +        subject { slice.to_s }
@@ -2522,7 +2962,7 @@ index 0000000..ef41d35
 +        Marshal.dump(slice)
 +      end
 +      context "when storing a line cache" do
-+        let(:slice) { described_class.new('foobar', 40, Parslet::Source::LineCache.new()) }
++        let(:slice) { cslice('foobar', 40, Parslet::Source::LineCache.new()) }
 +        it "should serialize" do
 +          Marshal.dump(slice)
 +        end
@@ -2531,12 +2971,9 @@ index 0000000..ef41d35
 +  end
 +end
 \ No newline at end of file
-diff --git a/spec/parslet/source/line_cache_spec.rb b/spec/parslet/source/line_cache_spec.rb
-new file mode 100644
-index 0000000..94626d2
 --- /dev/null
-+++ b/spec/parslet/source/line_cache_spec.rb
-@@ -0,0 +1,39 @@
++++ ruby-parslet/spec/parslet/source/line_cache_spec.rb
+@@ -0,0 +1,74 @@
 +require 'spec_helper'
 +
 +describe Parslet::Source::RangeSearch do
@@ -2576,13 +3013,44 @@ index 0000000..94626d2
 +    end
 +  end
 +end
-\ No newline at end of file
-diff --git a/spec/parslet/source_spec.rb b/spec/parslet/source_spec.rb
-new file mode 100644
-index 0000000..c50c11e
++
++describe Parslet::Source::LineCache do
++  describe "<- scan_for_line_endings" do
++    context "calculating the line_and_columns" do
++      let(:str) { "foo\nbar\nbazd" }
++
++      it "should return the first line if we have no line ends" do
++        subject.scan_for_line_endings(0, nil)
++        subject.line_and_column(3).should == [1, 4]
++
++        subject.scan_for_line_endings(0, "")
++        subject.line_and_column(5).should == [1, 6]
++      end
++
++      it "should find the right line starting from pos 0" do
++        subject.scan_for_line_endings(0, str)
++        subject.line_and_column(5).should == [2, 2]
++        subject.line_and_column(9).should == [3, 2]
++      end
++
++      it "should find the right line starting from pos 5" do
++        subject.scan_for_line_endings(5, str)
++        subject.line_and_column(11).should == [2, 3]
++      end
++
++      it "should find the right line if scannning the string multiple times" do
++        subject.scan_for_line_endings(0, str)
++        subject.scan_for_line_endings(0, "#{str}\nthe quick\nbrown fox")
++        subject.line_and_column(10).should == [3,3]
++        subject.line_and_column(24).should == [5,2]
++      end
++    end
++  end
++end
++
 --- /dev/null
-+++ b/spec/parslet/source_spec.rb
-@@ -0,0 +1,154 @@
++++ ruby-parslet/spec/parslet/source_spec.rb
+@@ -0,0 +1,168 @@
 +# Encoding: UTF-8
 +
 +require 'spec_helper'
@@ -2611,7 +3079,7 @@ index 0000000..c50c11e
 +      end
 +    end
 +    describe "<- #pos" do
-+      subject { source.pos }
++      subject { source.pos.charpos }
 +  
 +      it { should == 0 }
 +      context "after reading a few bytes" do
@@ -2621,22 +3089,27 @@ index 0000000..c50c11e
 +            pos += (n = rand(10)+1)
 +            source.consume(n)
 +  
-+            source.pos.should == pos
++            source.pos.charpos.should == pos
 +          end
 +        end 
 +      end
 +    end
 +    describe "<- #pos=(n)" do
-+      subject { source.pos }
++      subject { source.pos.charpos }
 +      10.times do
 +        pos = rand(200)
 +        context "setting position #{pos}" do
-+          before(:each) { source.pos = pos }
++          before(:each) { source.bytepos = pos }
 +  
 +          it { should == pos }
 +        end
 +      end
 +    end
++    describe '#chars_until' do
++      it 'should return 100 chars before line end' do
++        source.chars_until("\n").should == 100
++      end
++    end
 +    describe "<- #column & #line" do
 +      subject { source.line_and_column }
 +  
@@ -2658,24 +3131,24 @@ index 0000000..c50c11e
 +        before(:each) { source.consume(10000) }
 +  
 +        context "when seeking to 9" do
-+          before(:each) { source.pos = 9 }
++          before(:each) { source.bytepos = 9 }
 +          it { should == [1, 10] }
 +        end
 +        context "when seeking to 100" do
-+          before(:each) { source.pos = 100 }
++          before(:each) { source.bytepos = 100 }
 +          it { should == [1, 101] }
 +        end
 +        context "when seeking to 101" do
-+          before(:each) { source.pos = 101 }
++          before(:each) { source.bytepos = 101 }
 +          it { should == [2, 1] }
 +        end
 +        context "when seeking to 102" do
-+          before(:each) { source.pos = 102 }
++          before(:each) { source.bytepos = 102 }
 +          it { should == [2, 2] }
 +        end
 +        context "when seeking beyond eof" do
 +          it "should not throw an error" do
-+            source.pos = 1000
++            source.bytepos = 1000
 +          end 
 +        end
 +      end
@@ -2684,7 +3157,7 @@ index 0000000..c50c11e
 +        before(:each) { 
 +          @results = {}
 +          while source.chars_left>0
-+            pos = source.pos
++            pos = source.pos.charpos
 +            @results[pos] = source.line_and_column
 +            source.consume(1)
 +          end
@@ -2702,12 +3175,12 @@ index 0000000..c50c11e
 +        end
 +        it "should give the same results when seeking" do
 +          results.each do |pos, result|
-+            source.pos = pos
++            source.bytepos = pos
 +            source.line_and_column.should == result
 +          end
 +        end
 +        it "should give the same results when reading" do
-+          cur = source.pos = 0
++          cur = source.bytepos = 0
 +          while source.chars_left>0
 +            source.line_and_column.should == results[cur]
 +            cur += 1
@@ -2719,33 +3192,39 @@ index 0000000..c50c11e
 +    
 +  end
 +  
-+  describe "reading encoded input", :ruby => 1.9 do
++  describe "reading encoded input" do
 +    let(:source) { described_class.new("éö変わる") }
-+    
++
++    def r str
++      Regexp.new(Regexp.escape(str))
++    end
++  
 +    it "should read characters, not bytes" do
-+      source.should match("é")
++      source.should match(r("é"))
 +      source.consume(1)
++      source.pos.charpos.should == 1
++      source.bytepos.should == 2
 +      
-+      source.should match("ö")
++      source.should match(r("ö"))
 +      source.consume(1)
++      source.pos.charpos.should == 2
++      source.bytepos.should == 4
 +      
-+      source.should match("変")
++      source.should match(r("変"))
 +      source.consume(1)
 +      
 +      source.consume(2)
 +      source.chars_left.should == 0
++      source.chars_left.should == 0
 +    end 
 +  end
 +end
-diff --git a/spec/parslet/transform/context_spec.rb b/spec/parslet/transform/context_spec.rb
-new file mode 100644
-index 0000000..4ecca3b
 --- /dev/null
-+++ b/spec/parslet/transform/context_spec.rb
++++ ruby-parslet/spec/parslet/transform/context_spec.rb
 @@ -0,0 +1,35 @@
 +require 'spec_helper'
 +
-+describe Parslet::Transform::Context do
++describe Parslet::Context do
 +  def context(*args)
 +    described_class.new(*args)
 +  end
@@ -2779,11 +3258,8 @@ index 0000000..4ecca3b
 +  end
 +end
 \ No newline at end of file
-diff --git a/spec/parslet/transform_spec.rb b/spec/parslet/transform_spec.rb
-new file mode 100644
-index 0000000..0a3af5a
 --- /dev/null
-+++ b/spec/parslet/transform_spec.rb
++++ ruby-parslet/spec/parslet/transform_spec.rb
 @@ -0,0 +1,144 @@
 +require 'spec_helper'
 +
@@ -2930,12 +3406,9 @@ index 0000000..0a3af5a
 +  end
 +end
 \ No newline at end of file
-diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
-new file mode 100644
-index 0000000..a2f1fc1
 --- /dev/null
-+++ b/spec/spec_helper.rb
-@@ -0,0 +1,24 @@
++++ ruby-parslet/spec/spec_helper.rb
+@@ -0,0 +1,29 @@
 +
 +require 'parslet'
 +
@@ -2960,4 +3433,9 @@ index 0000000..a2f1fc1
 +  end
 +  exception.cause
 +end
++
++def slet name, &block
++  let(name, &block)
++  subject(&block)
++end
 \ No newline at end of file
diff --git a/debian/patches/0002-Fix-Encoding.patch b/debian/patches/0002-Fix-Encoding.patch
deleted file mode 100644
index 6c032f1..0000000
--- a/debian/patches/0002-Fix-Encoding.patch
+++ /dev/null
@@ -1,20 +0,0 @@
-From: Youhei SASAKI <uwabami at gfd-dennou.org>
-Date: Mon, 27 Jan 2014 13:27:48 +0900
-Subject: Fix Encoding
-
-Signed-off-by: Youhei SASAKI <uwabami at gfd-dennou.org>
----
- example/sentence.rb | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/example/sentence.rb b/example/sentence.rb
-index b73d140..fdd3b7f 100644
---- a/example/sentence.rb
-+++ b/example/sentence.rb
-@@ -1,5 +1,5 @@
- # encoding: UTF-8
--
-+Encoding.default_internal = "UTF-8"
- # A small example contributed by John Mettraux (jmettraux) that demonstrates
- # working with Unicode. This only works on Ruby 1.9.
- 
diff --git a/debian/patches/series b/debian/patches/series
index 755776d..b4fa6cb 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,2 +1 @@
 0001-Import-rspec-gemspec-from-upstream-Git-repo.patch
-0002-Fix-Encoding.patch

-- 
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