parslet 1.7.1 → 1.8.0

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.
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')