parslet 1.2.1 → 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Gemfile CHANGED
@@ -1,15 +1,16 @@
1
- # A sample Gemfile
2
1
  source "http://rubygems.org"
3
2
 
3
+ gem 'rake'
4
4
  gem 'blankslate', '~> 2'
5
5
 
6
6
  group :development do
7
7
  gem 'rspec'
8
8
  gem 'flexmock'
9
-
9
+
10
+ gem 'rdoc'
10
11
  gem 'sdoc'
11
12
 
12
13
  gem 'guard'
13
14
  gem 'guard-rspec'
14
15
  gem 'growl'
15
- end
16
+ end
@@ -3,9 +3,13 @@
3
3
  - prsnt? and absnt? are now finally banned into oblivion. Wasting vocals for
4
4
  the win.
5
5
 
6
- = 1.3.0 / ???
6
+ = 1.2.3 / 22Sep2011
7
7
 
8
- Next bigger release, features not clear yet. Probably heredoc-parsing.
8
+ + Transform#apply can now be called with a hash as second argument. This
9
+ provides bindings and a way to inject context.
10
+
11
+ ! Fixes a bug thar modified parslet atoms in place, defeating oop chaining.
12
+ (#50)
9
13
 
10
14
  = 1.2.1 / 6Jun2011
11
15
 
data/README CHANGED
@@ -2,13 +2,13 @@ INTRODUCTION
2
2
 
3
3
  Parslet makes developing complex parsers easy. It does so by
4
4
 
5
- * providing the best <b>error reporting</b> possible
6
- * <b>not generating</b> reams of code for you to debug
5
+ * providing the best error reporting possible
6
+ * not generating reams of code for you to debug
7
7
 
8
- Parslet takes the long way around to make <b>your job</b> easier. It allows
9
- for incremental language construction. Often, you start out small,
10
- implementing the atoms of your language first; _parslet_ takes pride in making
11
- this possible.
8
+ Parslet takes the long way around to make your job easier. It allows for
9
+ incremental language construction. Often, you start out small, implementing
10
+ the atoms of your language first; _parslet_ takes pride in making this
11
+ possible.
12
12
 
13
13
  Eager to try this out? Please see the associated web site:
14
14
  http://kschiess.github.com/parslet
@@ -48,8 +48,11 @@ issues.
48
48
  Note that due to Ruby 1.8 internals, Unicode parsing is not supported on that
49
49
  version.
50
50
 
51
+ On Mac OS X Lion, ruby-1.8.7-p352 has been known to segfault. Use
52
+ ruby-1.8.7-p334 for better results.
53
+
51
54
  STATUS
52
55
 
53
- At version 1.2.1 - See HISTORY.txt for changes.
56
+ At version 1.2.3 - See HISTORY.txt for changes.
54
57
 
55
58
  (c) 2010 Kaspar Schiess
data/Rakefile CHANGED
@@ -1,7 +1,8 @@
1
- require "rubygems"
2
- require "rake/rdoctask"
1
+ require 'rdoc/task'
2
+ require 'sdoc'
3
+
3
4
  require 'rspec/core/rake_task'
4
- require "rake/gempackagetask"
5
+ require "rubygems/package_task"
5
6
 
6
7
  desc "Run all tests: Exhaustive."
7
8
  RSpec::Core::RakeTask.new
@@ -15,10 +16,8 @@ end
15
16
 
16
17
  task :default => :spec
17
18
 
18
- require 'sdoc'
19
-
20
19
  # Generate documentation
21
- Rake::RDocTask.new do |rdoc|
20
+ RDoc::Task.new do |rdoc|
22
21
  rdoc.title = "parslet - construction of parsers made easy"
23
22
  rdoc.options << '--line-numbers'
24
23
  rdoc.options << '--fmt' << 'shtml' # explictly set shtml generator
@@ -36,7 +35,7 @@ task :gem => :spec
36
35
  spec = eval(File.read('parslet.gemspec'))
37
36
 
38
37
  desc "Generate the gem package."
39
- Rake::GemPackageTask.new(spec) do |pkg|
38
+ Gem::PackageTask.new(spec) do |pkg|
40
39
  pkg.gem_spec = spec
41
40
  end
42
41
 
@@ -0,0 +1,33 @@
1
+ # A small example on how to make parslet ignore parts of the parse tree.
2
+
3
+ $:.unshift File.dirname(__FILE__) + "/../lib"
4
+ require 'parslet'
5
+
6
+ class IgnoreParslet < Parslet::Atoms::Base
7
+ def initialize(parslet)
8
+ @parslet = parslet
9
+ end
10
+ def to_s_inner(prec)
11
+ @parslet.to_s(prec)
12
+ end
13
+ def try(source, context)
14
+ result = @parslet.try(source, context)
15
+
16
+ return success(nil) unless result.error?
17
+ return result
18
+ end
19
+
20
+ end
21
+ module IgnoreDSL
22
+ def ignore
23
+ IgnoreParslet.new(self)
24
+ end
25
+ end
26
+
27
+ class Parslet::Atoms::Base
28
+ include IgnoreDSL
29
+ end
30
+
31
+ include Parslet
32
+ p (str('a') >> str('b').ignore >> str('c')).
33
+ parse('abc')
@@ -0,0 +1 @@
1
+ "ac"@0
@@ -4,5 +4,5 @@
4
4
 
5
5
  ((((())))): {:l=>"("@0, :m=>{:l=>"("@1, :m=>{:l=>"("@2, :m=>{:l=>"("@3, :m=>{:l=>"("@4, :m=>nil, :r=>")"@5}, :r=>")"@6}, :r=>")"@7}, :r=>")"@8}, :r=>")"@9} (5 parens)
6
6
 
7
- ((()): Failed to match sequence (l:'(' m:(BALANCED?)) at line 1 char 6.
7
+ ((()): Failed to match sequence (l:'(' m:(BALANCED?) r:')') at line 1 char 6.
8
8
 
@@ -27,8 +27,7 @@ class Parslet::Atoms::Alternative < Parslet::Atoms::Base
27
27
  # all here. This reduces the number of objects created.
28
28
  #+++
29
29
  def |(parslet) # :nodoc:
30
- @alternatives << parslet
31
- self
30
+ self.class.new(*@alternatives + [parslet])
32
31
  end
33
32
 
34
33
  def try(source, context) # :nodoc:
@@ -97,6 +97,10 @@ class Parslet::Atoms::Base
97
97
  # Takes a mixed value coming out of a parslet and converts it to a return
98
98
  # value for the user by dropping things and merging hashes.
99
99
  #
100
+ # Named is set to true if this result will be embedded in a Hash result from
101
+ # naming something using <code>.as(...)</code>. It changes the folding
102
+ # semantics of repetition.
103
+ #
100
104
  def flatten(value, named=false) # :nodoc:
101
105
  # Passes through everything that isn't an array of things
102
106
  return value unless value.instance_of? Array
@@ -16,8 +16,7 @@ class Parslet::Atoms::Sequence < Parslet::Atoms::Base
16
16
  end
17
17
 
18
18
  def >>(parslet) # :nodoc:
19
- @parslets << parslet
20
- self
19
+ self.class.new(* @parslets+[parslet])
21
20
  end
22
21
 
23
22
  def try(source, context) # :nodoc:
@@ -18,37 +18,23 @@
18
18
  # Note that Parslet::Pattern only matches at a given subtree; it wont try
19
19
  # to match recursively. To do that, please use Parslet::Transform.
20
20
  #
21
- class Parslet::Pattern
22
- autoload :Context, 'parslet/pattern/context'
23
-
21
+ class Parslet::Pattern
24
22
  def initialize(pattern)
25
23
  @pattern = pattern
26
24
  end
27
25
 
28
26
  # Decides if the given subtree matches this pattern. Returns the bindings
29
- # made on a successful match or nil if the match fails.
27
+ # made on a successful match or nil if the match fails. If you specify
28
+ # bindings to be a hash, the mappings in it will be treated like bindings
29
+ # made during an attempted match.
30
30
  #
31
- def match(subtree)
32
- bindings = {}
33
- return bindings if element_match(subtree, @pattern, bindings)
34
- end
35
-
36
- # Executes the block on the bindings obtained by #match, if such a match
37
- # can be made. Contains the logic that will switch to instance variables
38
- # depending on the arity of the block.
31
+ # Example:
39
32
  #
40
- #---
41
- # TODO This method should be in Transform.
33
+ # Pattern.new('a').match('a', :foo => 'bar') # => { :foo => 'bar' }
42
34
  #
43
- def call_on_match(bindings, block)
44
- if block
45
- if block.arity == 1
46
- return block.call(bindings)
47
- else
48
- context = Context.new(bindings)
49
- return context.instance_eval(&block)
50
- end
51
- end
35
+ def match(subtree, bindings=nil)
36
+ bindings = bindings && bindings.dup || Hash.new
37
+ return bindings if element_match(subtree, @pattern, bindings)
52
38
  end
53
39
 
54
40
  # Returns true if the tree element given by +tree+ matches the expression
@@ -3,16 +3,6 @@
3
3
  # any other string, except that it remembers where it came from (offset in
4
4
  # original input).
5
5
  #
6
- # Some slices also know what parent slice they are a small part of. This
7
- # allows the slice to be concatenated to other slices from the same buffer by
8
- # reslicing it against that original buffer.
9
- #
10
- # Why the complexity? Slices allow retaining offset information. This will
11
- # allow to assign line and column to each small bit of output from the parslet
12
- # parser. Also, while we keep that information, we might as well try to do
13
- # something useful with it. Reslicing the same buffers should in theory keep
14
- # buffer copies and allocations down.
15
- #
16
6
  # == Extracting line and column
17
7
  #
18
8
  # Using the #line_and_column method, you can extract the line and column in
@@ -32,27 +22,16 @@
32
22
  # These omissions are somewhat intentional. Rather than maintaining a full
33
23
  # delegation, we opt for a partial emulation that gets the job done.
34
24
  #
35
- # Note also that there are some things that work with strings that will never
36
- # work when using slices. For instance, you cannot concatenate slices that
37
- # aren't from the same source or that don't join up:
38
- #
39
- # Example:
40
- # big_slice = 'abcdef'
41
- # a = big_slice.slice(0, 2) # => "ab"@0
42
- # b = big_slice.slice(4, 2) # => "ef"@4
43
- #
44
- # a + b # raises Parslet::InvalidSliceOperation
45
- #
46
- # This avoids creating slices with impossible offsets or that are
47
- # discontinous.
48
- #
49
25
  class Parslet::Slice
50
26
  attr_reader :str, :offset
51
- attr_reader :source
27
+ attr_reader :line_cache
52
28
 
53
- def initialize(string, offset, source=nil)
29
+ # Construct a slice using a string, an offset and an optional line cache.
30
+ # The line cache should be able to answer to the #line_and_column message.
31
+ #
32
+ def initialize(string, offset, line_cache=nil)
54
33
  @str, @offset = string, offset
55
- @source = source
34
+ @line_cache = line_cache
56
35
  end
57
36
 
58
37
  # Compares slices to other slices or strings.
@@ -78,16 +57,16 @@ class Parslet::Slice
78
57
  # as the one of this slice.
79
58
  #
80
59
  def +(other)
81
- self.class.new(str + other.to_s, offset, source)
60
+ self.class.new(str + other.to_s, offset, line_cache)
82
61
  end
83
62
 
84
63
  # Returns a <line, column> tuple referring to the original input.
85
64
  #
86
65
  def line_and_column
87
- raise ArgumentError, "No source was given, cannot infer line and column." \
88
- unless source
66
+ raise ArgumentError, "No line cache was given, cannot infer line and column." \
67
+ unless line_cache
89
68
 
90
- source.line_and_column(self.offset)
69
+ line_cache.line_and_column(self.offset)
91
70
  end
92
71
 
93
72
 
@@ -20,8 +20,7 @@ class Parslet::Source
20
20
  # Reads n chars from the input and returns a Range instance.
21
21
  #
22
22
  def read(n)
23
- raise ArgumentError, "Cannot read <= 1 characters at a time." \
24
- if n < 1
23
+ raise ArgumentError, "Cannot read < 1 characters at a time." if n < 1
25
24
  read_slice(n)
26
25
  end
27
26
 
@@ -51,7 +50,7 @@ private
51
50
  # cache line ends
52
51
  @line_cache.scan_for_line_endings(start, buf)
53
52
 
54
- Parslet::Slice.new(buf || '', start, self)
53
+ Parslet::Slice.new(buf || '', start, @line_cache)
55
54
  end
56
55
 
57
56
  if RUBY_VERSION !~ /^1.9/
@@ -62,7 +61,7 @@ private
62
61
  # cache line ends
63
62
  @line_cache.scan_for_line_endings(start, buf)
64
63
 
65
- Parslet::Slice.new(buf || '', start, self)
64
+ Parslet::Slice.new(buf || '', start, @line_cache)
66
65
  end
67
66
  end
68
- end
67
+ end
@@ -70,7 +70,6 @@ class Parslet::Source
70
70
  left = 0
71
71
  right = size - 1
72
72
 
73
- n = 10
74
73
  loop do
75
74
  mid = left + (right - left) / 2
76
75
 
@@ -87,4 +86,4 @@ class Parslet::Source
87
86
  end
88
87
  end
89
88
  end
90
- end
89
+ end
@@ -85,10 +85,38 @@ require 'parslet/pattern'
85
85
  # end
86
86
  # transform.apply(tree)
87
87
  #
88
+ # = Execution context
89
+ #
90
+ # The execution context of action blocks differs depending on the arity of
91
+ # said blocks. This can be confusing. It is however somewhat intentional. You
92
+ # should not create fat Transform descendants containing a lot of helper methods,
93
+ # instead keep your AST class construction in global scope or make it available
94
+ # through a factory. The following piece of code illustrates usage of global
95
+ # scope:
96
+ #
97
+ # transform = Parslet::Transform.new do
98
+ # rule(...) { AstNode.new(a_variable) }
99
+ # rule(...) { Ast.node(a_variable) } # modules are nice
100
+ # end
101
+ # transform.apply(tree)
102
+ #
103
+ # And here's how you would use a class builder (a factory):
104
+ #
105
+ # transform = Parslet::Transform.new do
106
+ # rule(...) { builder.add_node(a_variable) }
107
+ # rule(...) { |d| d[:builder].add_node(d[:a_variable]) }
108
+ # end
109
+ # transform.apply(tree, :builder => Builder.new)
110
+ #
111
+ # As you can see, Transform allows you to inject local context for your rule
112
+ # action blocks to use.
113
+ #
88
114
  class Parslet::Transform
89
115
  # FIXME: Maybe only part of it? Or maybe only include into constructor
90
116
  # context?
91
117
  include Parslet
118
+
119
+ autoload :Context, 'parslet/transform/context'
92
120
 
93
121
  class << self
94
122
  # FIXME: Only do this for subclasses?
@@ -133,19 +161,45 @@ class Parslet::Transform
133
161
  # or a simple parslet. Transformation will proceed down the tree, replacing
134
162
  # parts/all of it with new objects. The resulting object will be returned.
135
163
  #
136
- def apply(obj)
164
+ def apply(obj, context=nil)
137
165
  transform_elt(
138
166
  case obj
139
167
  when Hash
140
- recurse_hash(obj)
168
+ recurse_hash(obj, context)
141
169
  when Array
142
- recurse_array(obj)
170
+ recurse_array(obj, context)
143
171
  else
144
172
  obj
145
- end
173
+ end,
174
+ context
146
175
  )
147
176
  end
148
177
 
178
+ # Executes the block on the bindings obtained by Pattern#match, if such a match
179
+ # can be made. Depending on the arity of the given block, it is called in
180
+ # one of two environments: the current one or a clean toplevel environment.
181
+ #
182
+ # If you would like the current environment preserved, please use the
183
+ # arity 1 variant of the block. Alternatively, you can inject a context object
184
+ # and call methods on it (think :ctx => self).
185
+ #
186
+ # Example:
187
+ # # the local variable a is simulated
188
+ # t.call_on_match(:a => :b) { a }
189
+ # # no change of environment here
190
+ # t.call_on_match(:a => :b) { |d| d[:a] }
191
+ #
192
+ def call_on_match(bindings, block)
193
+ if block
194
+ if block.arity == 1
195
+ return block.call(bindings)
196
+ else
197
+ context = Context.new(bindings)
198
+ return context.instance_eval(&block)
199
+ end
200
+ end
201
+ end
202
+
149
203
  # Allow easy access to all rules, the ones defined in the instance and the
150
204
  # ones predefined in a subclass definition.
151
205
  #
@@ -153,24 +207,24 @@ class Parslet::Transform
153
207
  self.class.rules + @rules
154
208
  end
155
209
 
156
- def transform_elt(elt) # :nodoc:
210
+ def transform_elt(elt, context) # :nodoc:
157
211
  rules.each do |pattern, block|
158
- if bindings=pattern.match(elt)
212
+ if bindings=pattern.match(elt, context)
159
213
  # Produces transformed value
160
- return pattern.call_on_match(bindings, block)
214
+ return call_on_match(bindings, block)
161
215
  end
162
216
  end
163
217
 
164
218
  # No rule matched - element is not transformed
165
219
  return elt
166
220
  end
167
- def recurse_hash(hsh) # :nodoc:
221
+ def recurse_hash(hsh, ctx) # :nodoc:
168
222
  hsh.inject({}) do |new_hsh, (k,v)|
169
- new_hsh[k] = apply(v)
223
+ new_hsh[k] = apply(v, ctx)
170
224
  new_hsh
171
225
  end
172
226
  end
173
- def recurse_array(ary) # :nodoc:
174
- ary.map { |elt| apply(elt) }
227
+ def recurse_array(ary, ctx) # :nodoc:
228
+ ary.map { |elt| apply(elt, ctx) }
175
229
  end
176
230
  end
@@ -10,7 +10,7 @@ require 'blankslate'
10
10
  # a # => :b
11
11
  # end
12
12
  #
13
- class Parslet::Pattern::Context < BlankSlate # :nodoc:
13
+ class Parslet::Transform::Context < BlankSlate # :nodoc:
14
14
  def initialize(bindings)
15
15
  @bindings = bindings
16
16
  end
metadata CHANGED
@@ -1,70 +1,78 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: parslet
3
- version: !ruby/object:Gem::Version
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.2.3
4
5
  prerelease:
5
- version: 1.2.1
6
6
  platform: ruby
7
- authors:
7
+ authors:
8
8
  - Kaspar Schiess
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
-
13
- date: 2011-06-05 00:00:00 Z
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
12
+ date: 2011-09-22 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
16
15
  name: blankslate
17
- prerelease: false
18
- requirement: &id001 !ruby/object:Gem::Requirement
16
+ requirement: &70142555622900 !ruby/object:Gem::Requirement
19
17
  none: false
20
- requirements:
18
+ requirements:
21
19
  - - ~>
22
- - !ruby/object:Gem::Version
23
- version: "2.0"
20
+ - !ruby/object:Gem::Version
21
+ version: '2.0'
24
22
  type: :runtime
25
- version_requirements: *id001
26
- - !ruby/object:Gem::Dependency
27
- name: rspec
28
23
  prerelease: false
29
- requirement: &id002 !ruby/object:Gem::Requirement
24
+ version_requirements: *70142555622900
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ requirement: &70142555622120 !ruby/object:Gem::Requirement
30
28
  none: false
31
- requirements:
32
- - - ">="
33
- - !ruby/object:Gem::Version
34
- version: "0"
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
35
33
  type: :development
36
- version_requirements: *id002
37
- - !ruby/object:Gem::Dependency
34
+ prerelease: false
35
+ version_requirements: *70142555622120
36
+ - !ruby/object:Gem::Dependency
38
37
  name: flexmock
38
+ requirement: &70142555621000 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
39
45
  prerelease: false
40
- requirement: &id003 !ruby/object:Gem::Requirement
46
+ version_requirements: *70142555621000
47
+ - !ruby/object:Gem::Dependency
48
+ name: rdoc
49
+ requirement: &70142555620020 !ruby/object:Gem::Requirement
41
50
  none: false
42
- requirements:
43
- - - ">="
44
- - !ruby/object:Gem::Version
45
- version: "0"
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
46
55
  type: :development
47
- version_requirements: *id003
48
- - !ruby/object:Gem::Dependency
49
- name: sdoc
50
56
  prerelease: false
51
- requirement: &id004 !ruby/object:Gem::Requirement
57
+ version_requirements: *70142555620020
58
+ - !ruby/object:Gem::Dependency
59
+ name: sdoc
60
+ requirement: &70142555618980 !ruby/object:Gem::Requirement
52
61
  none: false
53
- requirements:
54
- - - ">="
55
- - !ruby/object:Gem::Version
56
- version: "0"
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
57
66
  type: :development
58
- version_requirements: *id004
67
+ prerelease: false
68
+ version_requirements: *70142555618980
59
69
  description:
60
70
  email: kaspar.schiess@absurd.li
61
71
  executables: []
62
-
63
72
  extensions: []
64
-
65
- extra_rdoc_files:
73
+ extra_rdoc_files:
66
74
  - README
67
- files:
75
+ files:
68
76
  - Gemfile
69
77
  - HISTORY.txt
70
78
  - LICENSE
@@ -91,12 +99,12 @@ files:
91
99
  - lib/parslet/expression.rb
92
100
  - lib/parslet/parser.rb
93
101
  - lib/parslet/pattern/binding.rb
94
- - lib/parslet/pattern/context.rb
95
102
  - lib/parslet/pattern.rb
96
103
  - lib/parslet/rig/rspec.rb
97
104
  - lib/parslet/slice.rb
98
105
  - lib/parslet/source/line_cache.rb
99
106
  - lib/parslet/source.rb
107
+ - lib/parslet/transform/context.rb
100
108
  - lib/parslet/transform.rb
101
109
  - lib/parslet.rb
102
110
  - example/boolean_algebra.rb
@@ -105,6 +113,7 @@ files:
105
113
  - example/email_parser.rb
106
114
  - example/empty.rb
107
115
  - example/erb.rb
116
+ - example/ignore.rb
108
117
  - example/ip_address.rb
109
118
  - example/json.rb
110
119
  - example/local.rb
@@ -116,6 +125,7 @@ files:
116
125
  - example/output/email_parser.out
117
126
  - example/output/empty.err
118
127
  - example/output/erb.out
128
+ - example/output/ignore.out
119
129
  - example/output/ip_address.out
120
130
  - example/output/json.out
121
131
  - example/output/local.out
@@ -136,31 +146,31 @@ files:
136
146
  - example/test.lit
137
147
  homepage: http://kschiess.github.com/parslet
138
148
  licenses: []
139
-
140
149
  post_install_message:
141
- rdoc_options:
150
+ rdoc_options:
142
151
  - --main
143
152
  - README
144
- require_paths:
153
+ require_paths:
145
154
  - lib
146
- required_ruby_version: !ruby/object:Gem::Requirement
155
+ required_ruby_version: !ruby/object:Gem::Requirement
147
156
  none: false
148
- requirements:
149
- - - ">="
150
- - !ruby/object:Gem::Version
151
- version: "0"
152
- required_rubygems_version: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - ! '>='
159
+ - !ruby/object:Gem::Version
160
+ version: '0'
161
+ segments:
162
+ - 0
163
+ hash: 4497395910031021567
164
+ required_rubygems_version: !ruby/object:Gem::Requirement
153
165
  none: false
154
- requirements:
155
- - - ">="
156
- - !ruby/object:Gem::Version
157
- version: "0"
166
+ requirements:
167
+ - - ! '>='
168
+ - !ruby/object:Gem::Version
169
+ version: '0'
158
170
  requirements: []
159
-
160
171
  rubyforge_project:
161
- rubygems_version: 1.8.5
172
+ rubygems_version: 1.8.6
162
173
  signing_key:
163
174
  specification_version: 3
164
175
  summary: Parser construction library with great error reporting in Ruby.
165
176
  test_files: []
166
-