parslet 1.7.1 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 546221c33c4829eb1bede8a241b40418197462de
4
- data.tar.gz: d440cbbac367cf7909bdeeb764b431bc3a32bdf7
3
+ metadata.gz: 930ed2d329af700f3465739d6db3e2897ef64fbc
4
+ data.tar.gz: ea14cb80ebd03f9b6b9e55aa461021ffaa79a622
5
5
  SHA512:
6
- metadata.gz: adae2aa91f57458cf679d60c3aefd5545a02f99895745cfc61e05290e86cae69adc1b38c121756e96beb4c6ffb4bce375af04e39050ecfe59154ecd3e187a76a
7
- data.tar.gz: f8eeac537a6b4dcc958efeb1355d4ad6040e88e91efa2e0397706803ba58c42f69b970720b62cae7f29ff550f50e652c984853af41cab31da7a6ebb4cccbc4ae
6
+ metadata.gz: 0872f8510339d1dfd97c4060ac4298115f2270765b192804e7722e27f93c90df38b915af6cc867792ecfca3137fd8291b4d7ac854b20849884dd9214185d837f
7
+ data.tar.gz: 76bb599af2b8df83c53dccbc4bd49652b1a49c3046c9e5bd6f37dd8e30dfe66db07142eb66032886cf0dd78b55bb3763840962d6c41b956e8394e3ca2bd7fcf4
@@ -1,7 +1,21 @@
1
+
1
2
  = 2.0 / ?? (future release changes, like a reminder to self)
2
3
 
3
4
  - prsnt? and absnt? are now finally banned into oblivion. Wasting vocals for
4
5
  the win.
6
+
7
+ = 1.8 / 3Apr2017
8
+
9
+ + The `ignored` atom that allows to ignore a part of the matched text.
10
+ `str('foo').ignore` will match 'foo', but not yield any parse output.
11
+ Thanks to chrismwendt (Chris Wendt).
12
+ + Infix expression parser (arithmetics, anyone?) now supports custom reducers
13
+ in block form. Thanks to chrismwendt (Chris Wendt).
14
+ ! Small patches to memory footprint (Christophe Bliard).
15
+ - blankslate dependency removed. You should be good - but if things break,
16
+ please let us know (Nikita Shilnikov).
17
+ ! Parslet now has `parse_failure_cause`, replaces the earlier `cause`.
18
+ ! Fixes all these interpreter warnings on modern rubies.
5
19
 
6
20
  = 1.7 / 12Mar2015
7
21
 
@@ -55,13 +55,13 @@ module Parslet
55
55
 
56
56
  # Raised when the parse failed to match. It contains the message that should
57
57
  # be presented to the user. More details can be extracted from the
58
- # exceptions #cause member: It contains an instance of {Parslet::Cause} that
58
+ # exceptions #parse_failure_cause member: It contains an instance of {Parslet::Cause} that
59
59
  # stores all the details of your failed parse in a tree structure.
60
60
  #
61
61
  # begin
62
62
  # parslet.parse(str)
63
63
  # rescue Parslet::ParseFailed => failure
64
- # puts failure.cause.ascii_tree
64
+ # puts failure.parse_failure_cause.ascii_tree
65
65
  # end
66
66
  #
67
67
  # Alternatively, you can just require 'parslet/convenience' and call the
@@ -72,15 +72,15 @@ module Parslet
72
72
  # parslet.parse_with_debug(str)
73
73
  #
74
74
  class ParseFailed < StandardError
75
- def initialize(message, cause=nil)
75
+ def initialize(message, parse_failure_cause=nil)
76
76
  super(message)
77
- @cause = cause
77
+ @parse_failure_cause = parse_failure_cause
78
78
  end
79
79
 
80
80
  # Why the parse failed.
81
81
  #
82
82
  # @return [Parslet::Cause]
83
- attr_reader :cause
83
+ attr_reader :parse_failure_cause
84
84
  end
85
85
 
86
86
  module ClassMethods
@@ -100,6 +100,7 @@ module Parslet
100
100
  # end
101
101
  #
102
102
  def rule(name, opts={}, &definition)
103
+ undef_method name if method_defined? name
103
104
  define_method(name) do
104
105
  @rules ||= {} # <name, rule> memoization
105
106
  return @rules[name] if @rules.has_key?(name)
@@ -217,18 +218,26 @@ module Parslet
217
218
  # associativity is chosen, it would be interpreted as '1 + (2 + 3)'. Note
218
219
  # that the hash trees output reflect that choice as well.
219
220
  #
220
- # Example:
221
+ # An optional block can be provided in order to manipulate the generated tree.
222
+ # The block will be called on each operator and passed 3 arguments: the left
223
+ # operand, the operator, and the right operand.
224
+ #
225
+ # Examples:
221
226
  # infix_expression(integer, [add_op, 1, :left])
222
227
  # # would parse things like '1 + 2'
223
228
  #
229
+ # infix_expression(integer, [add_op, 1, :left]) { |l,o,r| { :plus => [l, r] } }
230
+ # # would parse '1 + 2 + 3' as:
231
+ # # { :plus => [1, { :plus => [2, 3] }] }
232
+ #
224
233
  # @param element [Parslet::Atoms::Base] elements that take the NUMBER position
225
234
  # in the expression
226
235
  # @param operations [Array<(Parslet::Atoms::Base, Integer, {:left, :right})>]
227
236
  #
228
237
  # @see Parslet::Atoms::Infix
229
238
  #
230
- def infix_expression(element, *operations)
231
- Parslet::Atoms::Infix.new(element, operations)
239
+ def infix_expression(element, *operations, &reducer)
240
+ Parslet::Atoms::Infix.new(element, operations, &reducer)
232
241
  end
233
242
  module_function :infix_expression
234
243
 
@@ -299,4 +308,4 @@ require 'parslet/pattern/binding'
299
308
  require 'parslet/transform'
300
309
  require 'parslet/parser'
301
310
  require 'parslet/error_reporter'
302
- require 'parslet/scope'
311
+ require 'parslet/scope'
@@ -77,6 +77,7 @@ module Parslet::Accelerator
77
77
  def join_or_new tag, other_expr
78
78
  if type == tag
79
79
  @args << other_expr
80
+ self
80
81
  else
81
82
  Expression.new(tag, self, other_expr)
82
83
  end
@@ -19,6 +19,7 @@ module Parslet::Atoms
19
19
  require 'parslet/atoms/context'
20
20
  require 'parslet/atoms/dsl'
21
21
  require 'parslet/atoms/base'
22
+ require 'parslet/atoms/ignored'
22
23
  require 'parslet/atoms/named'
23
24
  require 'parslet/atoms/lookahead'
24
25
  require 'parslet/atoms/alternative'
@@ -83,7 +83,7 @@ class Parslet::Atoms::Base
83
83
  def apply(source, context, consume_all=false)
84
84
  old_pos = source.bytepos
85
85
 
86
- success, value = result = context.try_with_cache(self, source, consume_all)
86
+ success, _ = result = context.try_with_cache(self, source, consume_all)
87
87
 
88
88
  if success
89
89
  # Notify context
@@ -137,7 +137,7 @@ class Parslet::Atoms::Base
137
137
  end
138
138
  precedence BASE
139
139
  def to_s(outer_prec=OUTER)
140
- str = @label || to_s_inner(precedence)
140
+ str = label || to_s_inner(precedence)
141
141
  if outer_prec < precedence
142
142
  "(#{str})"
143
143
  else
@@ -120,7 +120,7 @@ module Parslet::Atoms
120
120
  return [] if named && list.empty?
121
121
 
122
122
  # If there are only strings, concatenate them and return that.
123
- foldl(list) { |s,e| s+e }
123
+ foldl(list.compact) { |s,e| s+e }
124
124
  end
125
125
 
126
126
  # That annoying warning 'Duplicate subtrees while merging result' comes
@@ -35,6 +35,17 @@ module Parslet::Atoms::DSL
35
35
  Parslet::Atoms::Repetition.new(self, 0, 1, :maybe)
36
36
  end
37
37
 
38
+ # Returns a new parslet atom that will not show up in the output. This
39
+ # is synonymous to calling #repeat(0,1). Generated tree value will always be
40
+ # nil.
41
+ #
42
+ # Example:
43
+ # str('foo').ignore
44
+ #
45
+ def ignore
46
+ Parslet::Atoms::Ignored.new(self)
47
+ end
48
+
38
49
  # Chains two parslet atoms together as a sequence.
39
50
  #
40
51
  # Example:
@@ -16,6 +16,7 @@ class Parslet::Atoms::Entity < Parslet::Atoms::Base
16
16
  @name = name
17
17
  @label = label
18
18
  @block = block
19
+ @parslet = nil
19
20
  end
20
21
 
21
22
  def try(source, context, consume_all)
@@ -0,0 +1,26 @@
1
+ # Ignores the result of a match.
2
+ #
3
+ # Example:
4
+ #
5
+ # str('foo') # will return 'foo',
6
+ # str('foo').ignore # will return nil
7
+ #
8
+ class Parslet::Atoms::Ignored < Parslet::Atoms::Base
9
+ attr_reader :parslet
10
+ def initialize(parslet)
11
+ super()
12
+
13
+ @parslet = parslet
14
+ end
15
+
16
+ def apply(source, context, consume_all)
17
+ success, _ = result = parslet.apply(source, context, consume_all)
18
+
19
+ return result unless success
20
+ succ(nil)
21
+ end
22
+
23
+ def to_s_inner(prec)
24
+ "ignored(#{parslet.to_s(prec)})"
25
+ end
26
+ end
@@ -1,11 +1,12 @@
1
1
  class Parslet::Atoms::Infix < Parslet::Atoms::Base
2
- attr_reader :element, :operations
2
+ attr_reader :element, :operations, :reducer
3
3
 
4
- def initialize(element, operations)
4
+ def initialize(element, operations, &reducer)
5
5
  super()
6
6
 
7
7
  @element = element
8
8
  @operations = operations
9
+ @reducer = reducer || lambda { |left, op, right| {l: left, o: op, r: right} }
9
10
  end
10
11
 
11
12
  def try(source, context, consume_all)
@@ -31,9 +32,9 @@ class Parslet::Atoms::Infix < Parslet::Atoms::Base
31
32
 
32
33
  if right.kind_of? Array
33
34
  # Subexpression -> Subhash
34
- left = {l: left, o: op, r: produce_tree(right)}
35
+ left = reducer.call(left, op, produce_tree(right))
35
36
  else
36
- left = {l: left, o: op, r: right}
37
+ left = reducer.call(left, op, right)
37
38
  end
38
39
  end
39
40
 
@@ -25,7 +25,7 @@ class Parslet::Atoms::Lookahead < Parslet::Atoms::Base
25
25
  rewind_pos = source.bytepos
26
26
  error_pos = source.pos
27
27
 
28
- success, value = bound_parslet.apply(source, context, consume_all)
28
+ success, _ = bound_parslet.apply(source, context, consume_all)
29
29
 
30
30
  if positive
31
31
  return succ(nil) if success
@@ -5,8 +5,8 @@ module Parslet
5
5
  #
6
6
  class Cause
7
7
  def initialize(message, source, pos, children)
8
- @message, @source, @pos, @children =
9
- message, source, pos, children
8
+ @message, @source, @pos, @children, @context =
9
+ message, source, pos, children, nil
10
10
  end
11
11
 
12
12
  # @return [String, Array] A string or an array of message pieces that
@@ -1,5 +1,3 @@
1
- require 'blankslate'
2
-
3
1
  # Provides a context for tree transformations to run in. The context allows
4
2
  # accessing each of the bindings in the bindings hash as local method.
5
3
  #
@@ -11,24 +9,12 @@ require 'blankslate'
11
9
  # end
12
10
  #
13
11
  # @api private
14
- class Parslet::Context < BlankSlate
15
- reveal :methods
16
- reveal :respond_to?
17
- reveal :inspect
18
- reveal :to_s
19
- reveal :instance_variable_set
20
-
12
+ class Parslet::Context
21
13
  include Parslet
22
-
23
- def meta_def(name, &body)
24
- metaclass = class << self; self; end
25
14
 
26
- metaclass.send(:define_method, name, &body)
27
- end
28
-
29
15
  def initialize(bindings)
30
16
  bindings.each do |key, value|
31
- meta_def(key.to_sym) { value }
17
+ singleton_class.send(:define_method, key) { value }
32
18
  instance_variable_set("@#{key}", value)
33
19
  end
34
20
  end
@@ -5,7 +5,7 @@ class Parslet::Atoms::Base
5
5
  # begin
6
6
  # tree = parser.parse('something')
7
7
  # rescue Parslet::ParseFailed => error
8
- # puts parser.cause.ascii_tree
8
+ # puts parser.parse_failure_cause.ascii_tree
9
9
  # end
10
10
  #
11
11
  # into a convenient method.
@@ -27,7 +27,7 @@ class Parslet::Atoms::Base
27
27
  def parse_with_debug str, opts={}
28
28
  parse str, opts
29
29
  rescue Parslet::ParseFailed => error
30
- puts error.cause.ascii_tree
30
+ puts error.parse_failure_cause.ascii_tree
31
31
  end
32
32
 
33
33
  end
@@ -64,7 +64,7 @@ module Parslet
64
64
  # current deepest error that was saved as a reference.
65
65
  #
66
66
  def deepest(cause)
67
- rank, leaf = deepest_child(cause)
67
+ _, leaf = deepest_child(cause)
68
68
 
69
69
  if !deepest_cause || leaf.pos >= deepest_cause.pos
70
70
  # This error reaches deeper into the input, save it as reference.
@@ -51,6 +51,7 @@ class Parslet::Parser < Parslet::Atoms::Base
51
51
  # end
52
52
  #
53
53
  def root(name)
54
+ undef_method :root if method_defined? :root
54
55
  define_method(:root) do
55
56
  self.send(name)
56
57
  end
@@ -64,4 +65,4 @@ class Parslet::Parser < Parslet::Atoms::Base
64
65
  def to_s_inner(prec)
65
66
  root.to_s(prec)
66
67
  end
67
- end
68
+ end
@@ -48,11 +48,10 @@ class Parslet::Pattern
48
48
  #
49
49
  def element_match(tree, exp, bindings)
50
50
  # p [:elm, tree, exp]
51
- case [tree, exp].map { |e| e.class }
52
- when [Hash,Hash]
53
- return element_match_hash(tree, exp, bindings)
54
- when [Array,Array]
55
- return element_match_ary_single(tree, exp, bindings)
51
+ if tree.is_a?(Hash) && exp.is_a?(Hash)
52
+ return element_match_hash(tree, exp, bindings)
53
+ elsif tree.is_a?(Array) && exp.is_a?(Array)
54
+ return element_match_ary_single(tree, exp, bindings)
56
55
  else
57
56
  # If elements match exactly, then that is good enough in all cases
58
57
  return true if exp === tree
@@ -2,13 +2,6 @@ RSpec::Matchers.define(:parse) do |input, opts|
2
2
  as = block = nil
3
3
  result = trace = nil
4
4
 
5
- unless self.respond_to? :failure_message # if RSpec 2.x
6
- class << self
7
- alias_method :failure_message, :failure_message_for_should
8
- alias_method :failure_message_when_negated, :failure_message_for_should_not
9
- end
10
- end
11
-
12
5
  match do |parser|
13
6
  begin
14
7
  result = parser.parse(input)
@@ -16,12 +9,12 @@ RSpec::Matchers.define(:parse) do |input, opts|
16
9
  block.call(result) :
17
10
  (as == result || as.nil?)
18
11
  rescue Parslet::ParseFailed => ex
19
- trace = ex.cause.ascii_tree if opts && opts[:trace]
12
+ trace = ex.parse_failure_cause.ascii_tree if opts && opts[:trace]
20
13
  false
21
14
  end
22
15
  end
23
16
 
24
- failure_message do |is|
17
+ public_send(respond_to?(:failure_message) ? :failure_message : :failure_message_for_should) do |is|
25
18
  if block
26
19
  "expected output of parsing #{input.inspect}" <<
27
20
  " with #{is.inspect} to meet block conditions, but it didn't"
@@ -37,7 +30,7 @@ RSpec::Matchers.define(:parse) do |input, opts|
37
30
  end
38
31
  end
39
32
 
40
- failure_message_when_negated do |is|
33
+ public_send(respond_to?(:failure_message_when_negated) ? :failure_message_when_negated : :failure_message_for_should_not) do |is|
41
34
  if block
42
35
  "expected output of parsing #{input.inspect} with #{is.inspect} not to meet block conditions, but it did"
43
36
  else
@@ -52,8 +45,8 @@ RSpec::Matchers.define(:parse) do |input, opts|
52
45
 
53
46
  # NOTE: This has a nodoc tag since the rdoc parser puts this into
54
47
  # Object, a thing I would never allow.
55
- chain :as do |expected_output=nil, &block|
48
+ chain :as do |expected_output=nil, &my_block|
56
49
  as = expected_output
57
- block = block
50
+ block = my_block
58
51
  end
59
52
  end
@@ -105,6 +105,6 @@ class Parslet::Slice
105
105
  # Prints the slice as <code>"string"@offset</code>.
106
106
  def inspect
107
107
 
108
- str.inspect << "@#{offset}"
108
+ str.inspect + "@#{offset}"
109
109
  end
110
110
  end
@@ -10,6 +10,7 @@ class Parslet::Source
10
10
  # but probably make a scan to that position neccessary.
11
11
  @line_ends = []
12
12
  @line_ends.extend RangeSearch
13
+ @last_line_end = nil
13
14
  end
14
15
 
15
16
  # Returns a <line, column> tuple for the given input position. Input
@@ -131,7 +131,7 @@ class Parslet::Transform
131
131
  # Allows accessing the class' rules
132
132
  #
133
133
  def rules
134
- @__transform_rules || []
134
+ @__transform_rules ||= []
135
135
  end
136
136
 
137
137
  def inherited(subclass)
@@ -140,7 +140,8 @@ class Parslet::Transform
140
140
  end
141
141
  end
142
142
 
143
- def initialize(&block)
143
+ def initialize(raise_on_unmatch: false, &block)
144
+ @raise_on_unmatch = raise_on_unmatch
144
145
  @rules = []
145
146
 
146
147
  if block
@@ -236,7 +237,14 @@ class Parslet::Transform
236
237
  end
237
238
 
238
239
  # No rule matched - element is not transformed
239
- return elt
240
+ if @raise_on_unmatch && elt.is_a?(Hash)
241
+ elt_types = elt.map do |key, value|
242
+ [ key, value.class ]
243
+ end.to_h
244
+ raise NotImplementedError, "Failed to match `#{elt_types.inspect}`"
245
+ else
246
+ return elt
247
+ end
240
248
  end
241
249
 
242
250
  # @api private
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'parslet'
5
- s.version = '1.7.1'
5
+ s.version = '1.8.0'
6
6
 
7
7
  s.authors = ['Kaspar Schiess']
8
8
  s.email = 'kaspar.schiess@absurd.li'
@@ -12,7 +12,5 @@ Gem::Specification.new do |s|
12
12
  s.license = 'MIT'
13
13
  s.rdoc_options = ['--main', 'README']
14
14
  s.require_paths = ['lib']
15
- s.summary = 'Parser construction library with great error reporting in Ruby.'
16
-
17
- s.add_dependency 'blankslate', '>= 2.0', '<= 4.0'
15
+ s.summary = 'Parser construction library with great error reporting in Ruby.'
18
16
  end
@@ -12,7 +12,7 @@ describe "Regression on" do
12
12
  end
13
13
 
14
14
  it "runs successfully" do
15
- stdin, stdout, stderr = Open3.popen3("ruby #{example}")
15
+ _, stdout, stderr = Open3.popen3("ruby #{example}")
16
16
 
17
17
  handle_map = {
18
18
  stdout => :out,
@@ -21,7 +21,7 @@ describe "Regression on" do
21
21
  expectation_found = handle_map.any? do |io, ext|
22
22
  name = product_path(example, ext)
23
23
 
24
- if File.exists?(name)
24
+ if File.exist?(name)
25
25
  io.read.strip.should == File.read(name).strip
26
26
  true
27
27
  end
@@ -109,4 +109,13 @@ Don't know what to do with "%" at line 1 char 2.
109
109
  end
110
110
  end
111
111
  end
112
+ describe "providing a reducer block" do
113
+ class InfixExpressionReducerParser < Parslet::Parser
114
+ rule(:top) { infix_expression(str('a'), [str('-'), 1, :right]) { |l,o,r| {:and=>[l,r]} } }
115
+ end
116
+
117
+ it "applies the reducer" do
118
+ InfixExpressionReducerParser.new.top.parse("a-a-a").should == {:and=>["a", {:and=>["a", "a"]}]}
119
+ end
120
+ end
112
121
  end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe Parslet::Atoms::Ignored do
4
+ include Parslet
5
+
6
+ describe "ignore" do
7
+ it "ignores parts of the input" do
8
+ str('a').ignore.parse('a').should == nil
9
+ (str('a') >> str('b').ignore >> str('c')).parse('abc').should == 'ac'
10
+ (str('a') >> str('b').as(:name).ignore >> str('c')).parse('abc').should == 'ac'
11
+ (str('a') >> str('b').maybe.ignore >> str('c')).parse('abc').should == 'ac'
12
+ (str('a') >> str('b').maybe.ignore >> str('c')).parse('ac').should == 'ac'
13
+ end
14
+ end
15
+ end
@@ -225,7 +225,7 @@ describe Parslet do
225
225
 
226
226
  it "should not loop infinitely" do
227
227
  lambda {
228
- timeout(1) { parslet.parse('bar') }
228
+ Timeout.timeout(1) { parslet.parse('bar') }
229
229
  }.should raise_error(Parslet::ParseFailed)
230
230
  end
231
231
  end
@@ -398,7 +398,7 @@ describe Parslet do
398
398
  end
399
399
 
400
400
  describe "combinations thereof (regression)" do
401
- success=[
401
+ [
402
402
  [(str('a').repeat >> str('b').repeat), 'aaabbb']
403
403
  ].each do |(parslet, input)|
404
404
  describe "#{parslet.inspect} applied to #{input.inspect}" do
@@ -408,7 +408,7 @@ describe Parslet do
408
408
  end
409
409
  end
410
410
 
411
- inspection=[
411
+ [
412
412
  [str('a'), "'a'" ],
413
413
  [(str('a') | str('b')).maybe, "('a' / 'b')?" ],
414
414
  [(str('a') >> str('b')).maybe, "('a' 'b')?" ],
@@ -9,22 +9,6 @@ describe Parslet::Context do
9
9
  context(:a => 'value').instance_eval { a }.
10
10
  should == 'value'
11
11
  end
12
- describe 'when a method in BlankSlate is inherited from the environment somehow' do
13
- before(:each) { BlankSlate.send(:define_method, :a) { 'c' } }
14
- after(:each) { BlankSlate.send(:undef_method, :a) }
15
-
16
- it "masks what is already on blank slate" do
17
- context(:a => 'b').instance_eval { a }.
18
- should == 'b'
19
- end
20
- end
21
- it "should not reveal define_singleton_method for all users of blankslate, just for us" do
22
- expect {
23
- BlankSlate.new.instance_eval {
24
- define_singleton_method(:foo) { 'foo' }
25
- }
26
- }.to raise_error(NoMethodError)
27
- end
28
12
  it "one contexts variables aren't the next ones" do
29
13
  ca = context(:a => 'b')
30
14
  cb = context(:b => 'c')
@@ -32,4 +16,41 @@ describe Parslet::Context do
32
16
  ca.methods.should_not include(:b)
33
17
  cb.methods.should_not include(:a)
34
18
  end
19
+
20
+ describe 'works as a Ruby object should' do
21
+ let(:obj) { context(a: 1) }
22
+
23
+ it 'responds_to? :a' do
24
+ assert obj.respond_to?(:a)
25
+ end
26
+ it 'includes :a in #methods' do
27
+ obj.methods.assert.include?(:a)
28
+ end
29
+ it 'allows inspection' do
30
+ obj.inspect.assert.match(/@a=1/)
31
+ end
32
+ it 'allows conversion to string' do
33
+ obj.to_s.assert.match(/Parslet::Context:0x/)
34
+ end
35
+
36
+ context 'when the context is enhanced' do
37
+ before(:each) do
38
+ class << obj
39
+ def foo
40
+ 'foo'
41
+ end
42
+ end
43
+ end
44
+
45
+ it 'responds_to correctly' do
46
+ assert obj.respond_to?(:foo)
47
+ end
48
+ it 'includes :foo also in methods' do
49
+ obj.methods.assert.include?(:foo)
50
+ end
51
+ it 'allows calling #foo' do
52
+ obj.foo.assert == 'foo'
53
+ end
54
+ end
55
+ end
35
56
  end
@@ -6,10 +6,6 @@ describe Parslet::Transform do
6
6
  include Parslet
7
7
 
8
8
  let(:transform) { Parslet::Transform.new }
9
- attr_reader :transform
10
- before(:each) do
11
- @transform = Parslet::Transform.new
12
- end
13
9
 
14
10
  class A < Struct.new(:elt); end
15
11
  class B < Struct.new(:elt); end
@@ -77,6 +73,26 @@ describe Parslet::Transform do
77
73
  transform.apply(:a => 'a').should == A.new('a')
78
74
  end
79
75
 
76
+ context "optionally raise when no match found" do
77
+ class BumbleBee < Parslet::Transform
78
+ def initialize(&block)
79
+ super(raise_on_unmatch: true, &block)
80
+ end
81
+ rule(:a => simple(:x)) { A.new(x) }
82
+ end
83
+ let(:transform) { BumbleBee.new }
84
+
85
+ it "should evaluate rules" do
86
+ transform.apply(:a => 'a').should == A.new('a')
87
+ end
88
+
89
+ it "should raise when no rules are matched" do
90
+ lambda {
91
+ transform.apply(:z => 'z')
92
+ }.should raise_error(NotImplementedError, /Failed to match/)
93
+ end
94
+ end
95
+
80
96
  context "with inheritance" do
81
97
  class OptimusPrimeJunior < OptimusPrime
82
98
  rule(:b => simple(:x)) { B.new(x.upcase) }
@@ -137,7 +153,9 @@ describe Parslet::Transform do
137
153
  it "should execute in its own context" do
138
154
  @bar = 'test'
139
155
  transform.call_on_match(bindings, proc do
140
- @bar.should_not == 'test'
156
+ if instance_variable_defined?("@bar")
157
+ instance_variable_get("@bar").should_not == 'test'
158
+ end
141
159
  end)
142
160
  end
143
161
  end
@@ -5,6 +5,8 @@ require 'parslet/rig/rspec'
5
5
  require 'parslet/atoms/visitor'
6
6
  require 'parslet/export'
7
7
 
8
+ require 'ae'
9
+
8
10
  RSpec.configure do |config|
9
11
  config.mock_with :flexmock
10
12
 
@@ -29,7 +31,7 @@ def catch_failed_parse
29
31
  yield
30
32
  rescue Parslet::ParseFailed => exception
31
33
  end
32
- exception.cause
34
+ exception.parse_failure_cause
33
35
  end
34
36
 
35
37
  def slet name, &block
metadata CHANGED
@@ -1,35 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: parslet
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.1
4
+ version: 1.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kaspar Schiess
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-27 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: blankslate
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '2.0'
20
- - - "<="
21
- - !ruby/object:Gem::Version
22
- version: '4.0'
23
- type: :runtime
24
- prerelease: false
25
- version_requirements: !ruby/object:Gem::Requirement
26
- requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- version: '2.0'
30
- - - "<="
31
- - !ruby/object:Gem::Version
32
- version: '4.0'
11
+ date: 2017-04-03 00:00:00.000000000 Z
12
+ dependencies: []
33
13
  description:
34
14
  email: kaspar.schiess@absurd.li
35
15
  executables: []
@@ -51,7 +31,6 @@ files:
51
31
  - example/email_parser.rb
52
32
  - example/empty.rb
53
33
  - example/erb.rb
54
- - example/ignore.rb
55
34
  - example/ip_address.rb
56
35
  - example/json.rb
57
36
  - example/local.rb
@@ -111,6 +90,7 @@ files:
111
90
  - lib/parslet/atoms/dsl.rb
112
91
  - lib/parslet/atoms/dynamic.rb
113
92
  - lib/parslet/atoms/entity.rb
93
+ - lib/parslet/atoms/ignored.rb
114
94
  - lib/parslet/atoms/infix.rb
115
95
  - lib/parslet/atoms/lookahead.rb
116
96
  - lib/parslet/atoms/named.rb
@@ -154,6 +134,7 @@ files:
154
134
  - spec/parslet/atoms/combinations_spec.rb
155
135
  - spec/parslet/atoms/dsl_spec.rb
156
136
  - spec/parslet/atoms/entity_spec.rb
137
+ - spec/parslet/atoms/ignored_spec.rb
157
138
  - spec/parslet/atoms/infix_spec.rb
158
139
  - spec/parslet/atoms/lookahead_spec.rb
159
140
  - spec/parslet/atoms/named_spec.rb
@@ -206,8 +187,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
206
187
  version: '0'
207
188
  requirements: []
208
189
  rubyforge_project:
209
- rubygems_version: 2.4.5
190
+ rubygems_version: 2.6.4
210
191
  signing_key:
211
192
  specification_version: 4
212
193
  summary: Parser construction library with great error reporting in Ruby.
213
194
  test_files: []
195
+ has_rdoc:
@@ -1,33 +0,0 @@
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, consume_all)
14
- success, value = result = @parslet.try(source, context, consume_all)
15
-
16
- return succ(nil) if success
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')