plurimath-parslet 3.0.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.
Files changed (148) hide show
  1. checksums.yaml +7 -0
  2. data/HISTORY.txt +284 -0
  3. data/LICENSE +23 -0
  4. data/README.adoc +454 -0
  5. data/Rakefile +71 -0
  6. data/lib/parslet/accelerator/application.rb +62 -0
  7. data/lib/parslet/accelerator/engine.rb +112 -0
  8. data/lib/parslet/accelerator.rb +162 -0
  9. data/lib/parslet/atoms/alternative.rb +53 -0
  10. data/lib/parslet/atoms/base.rb +157 -0
  11. data/lib/parslet/atoms/can_flatten.rb +137 -0
  12. data/lib/parslet/atoms/capture.rb +38 -0
  13. data/lib/parslet/atoms/context.rb +103 -0
  14. data/lib/parslet/atoms/dsl.rb +112 -0
  15. data/lib/parslet/atoms/dynamic.rb +32 -0
  16. data/lib/parslet/atoms/entity.rb +45 -0
  17. data/lib/parslet/atoms/ignored.rb +26 -0
  18. data/lib/parslet/atoms/infix.rb +115 -0
  19. data/lib/parslet/atoms/lookahead.rb +52 -0
  20. data/lib/parslet/atoms/named.rb +32 -0
  21. data/lib/parslet/atoms/re.rb +41 -0
  22. data/lib/parslet/atoms/repetition.rb +87 -0
  23. data/lib/parslet/atoms/scope.rb +26 -0
  24. data/lib/parslet/atoms/sequence.rb +48 -0
  25. data/lib/parslet/atoms/str.rb +42 -0
  26. data/lib/parslet/atoms/visitor.rb +89 -0
  27. data/lib/parslet/atoms.rb +34 -0
  28. data/lib/parslet/cause.rb +101 -0
  29. data/lib/parslet/context.rb +21 -0
  30. data/lib/parslet/convenience.rb +33 -0
  31. data/lib/parslet/error_reporter/contextual.rb +120 -0
  32. data/lib/parslet/error_reporter/deepest.rb +100 -0
  33. data/lib/parslet/error_reporter/tree.rb +63 -0
  34. data/lib/parslet/error_reporter.rb +8 -0
  35. data/lib/parslet/export.rb +163 -0
  36. data/lib/parslet/expression/treetop.rb +92 -0
  37. data/lib/parslet/expression.rb +51 -0
  38. data/lib/parslet/graphviz.rb +97 -0
  39. data/lib/parslet/parser.rb +68 -0
  40. data/lib/parslet/pattern/binding.rb +49 -0
  41. data/lib/parslet/pattern.rb +113 -0
  42. data/lib/parslet/position.rb +21 -0
  43. data/lib/parslet/rig/rspec.rb +52 -0
  44. data/lib/parslet/scope.rb +42 -0
  45. data/lib/parslet/slice.rb +105 -0
  46. data/lib/parslet/source/line_cache.rb +99 -0
  47. data/lib/parslet/source.rb +96 -0
  48. data/lib/parslet/transform.rb +265 -0
  49. data/lib/parslet/version.rb +5 -0
  50. data/lib/parslet.rb +314 -0
  51. data/plurimath-parslet.gemspec +42 -0
  52. data/spec/acceptance/infix_parser_spec.rb +145 -0
  53. data/spec/acceptance/mixing_parsers_spec.rb +74 -0
  54. data/spec/acceptance/regression_spec.rb +329 -0
  55. data/spec/acceptance/repetition_and_maybe_spec.rb +44 -0
  56. data/spec/acceptance/unconsumed_input_spec.rb +21 -0
  57. data/spec/examples/boolean_algebra_spec.rb +257 -0
  58. data/spec/examples/calc_spec.rb +278 -0
  59. data/spec/examples/capture_spec.rb +137 -0
  60. data/spec/examples/comments_spec.rb +186 -0
  61. data/spec/examples/deepest_errors_spec.rb +420 -0
  62. data/spec/examples/documentation_spec.rb +205 -0
  63. data/spec/examples/email_parser_spec.rb +275 -0
  64. data/spec/examples/empty_spec.rb +37 -0
  65. data/spec/examples/erb_spec.rb +482 -0
  66. data/spec/examples/ip_address_spec.rb +153 -0
  67. data/spec/examples/json_spec.rb +413 -0
  68. data/spec/examples/local_spec.rb +302 -0
  69. data/spec/examples/mathn_spec.rb +151 -0
  70. data/spec/examples/minilisp_spec.rb +492 -0
  71. data/spec/examples/modularity_spec.rb +340 -0
  72. data/spec/examples/nested_errors_spec.rb +322 -0
  73. data/spec/examples/optimized_erb_spec.rb +299 -0
  74. data/spec/examples/parens_spec.rb +239 -0
  75. data/spec/examples/prec_calc_spec.rb +525 -0
  76. data/spec/examples/readme_spec.rb +228 -0
  77. data/spec/examples/scopes_spec.rb +187 -0
  78. data/spec/examples/seasons_spec.rb +196 -0
  79. data/spec/examples/sentence_spec.rb +119 -0
  80. data/spec/examples/simple_xml_spec.rb +250 -0
  81. data/spec/examples/string_parser_spec.rb +407 -0
  82. data/spec/fixtures/examples/boolean_algebra.rb +62 -0
  83. data/spec/fixtures/examples/calc.rb +86 -0
  84. data/spec/fixtures/examples/capture.rb +36 -0
  85. data/spec/fixtures/examples/comments.rb +22 -0
  86. data/spec/fixtures/examples/deepest_errors.rb +99 -0
  87. data/spec/fixtures/examples/documentation.rb +32 -0
  88. data/spec/fixtures/examples/email_parser.rb +42 -0
  89. data/spec/fixtures/examples/empty.rb +10 -0
  90. data/spec/fixtures/examples/erb.rb +39 -0
  91. data/spec/fixtures/examples/ip_address.rb +103 -0
  92. data/spec/fixtures/examples/json.rb +107 -0
  93. data/spec/fixtures/examples/local.rb +60 -0
  94. data/spec/fixtures/examples/mathn.rb +47 -0
  95. data/spec/fixtures/examples/minilisp.rb +75 -0
  96. data/spec/fixtures/examples/modularity.rb +60 -0
  97. data/spec/fixtures/examples/nested_errors.rb +95 -0
  98. data/spec/fixtures/examples/optimized_erb.rb +105 -0
  99. data/spec/fixtures/examples/parens.rb +25 -0
  100. data/spec/fixtures/examples/prec_calc.rb +71 -0
  101. data/spec/fixtures/examples/readme.rb +59 -0
  102. data/spec/fixtures/examples/scopes.rb +43 -0
  103. data/spec/fixtures/examples/seasons.rb +40 -0
  104. data/spec/fixtures/examples/sentence.rb +18 -0
  105. data/spec/fixtures/examples/simple_xml.rb +51 -0
  106. data/spec/fixtures/examples/string_parser.rb +77 -0
  107. data/spec/parslet/atom_results_spec.rb +39 -0
  108. data/spec/parslet/atoms/alternative_spec.rb +26 -0
  109. data/spec/parslet/atoms/base_spec.rb +127 -0
  110. data/spec/parslet/atoms/capture_spec.rb +21 -0
  111. data/spec/parslet/atoms/combinations_spec.rb +5 -0
  112. data/spec/parslet/atoms/dsl_spec.rb +7 -0
  113. data/spec/parslet/atoms/entity_spec.rb +77 -0
  114. data/spec/parslet/atoms/ignored_spec.rb +15 -0
  115. data/spec/parslet/atoms/infix_spec.rb +5 -0
  116. data/spec/parslet/atoms/lookahead_spec.rb +22 -0
  117. data/spec/parslet/atoms/named_spec.rb +4 -0
  118. data/spec/parslet/atoms/re_spec.rb +14 -0
  119. data/spec/parslet/atoms/repetition_spec.rb +24 -0
  120. data/spec/parslet/atoms/scope_spec.rb +26 -0
  121. data/spec/parslet/atoms/sequence_spec.rb +28 -0
  122. data/spec/parslet/atoms/str_spec.rb +15 -0
  123. data/spec/parslet/atoms/visitor_spec.rb +101 -0
  124. data/spec/parslet/atoms_spec.rb +488 -0
  125. data/spec/parslet/convenience_spec.rb +54 -0
  126. data/spec/parslet/error_reporter/contextual_spec.rb +118 -0
  127. data/spec/parslet/error_reporter/deepest_spec.rb +82 -0
  128. data/spec/parslet/error_reporter/tree_spec.rb +7 -0
  129. data/spec/parslet/export_spec.rb +40 -0
  130. data/spec/parslet/expression/treetop_spec.rb +74 -0
  131. data/spec/parslet/minilisp.citrus +29 -0
  132. data/spec/parslet/minilisp.tt +29 -0
  133. data/spec/parslet/parser_spec.rb +36 -0
  134. data/spec/parslet/parslet_spec.rb +38 -0
  135. data/spec/parslet/pattern_spec.rb +272 -0
  136. data/spec/parslet/position_spec.rb +14 -0
  137. data/spec/parslet/rig/rspec_spec.rb +54 -0
  138. data/spec/parslet/scope_spec.rb +45 -0
  139. data/spec/parslet/slice_spec.rb +186 -0
  140. data/spec/parslet/source/line_cache_spec.rb +74 -0
  141. data/spec/parslet/source_spec.rb +210 -0
  142. data/spec/parslet/transform/context_spec.rb +56 -0
  143. data/spec/parslet/transform_spec.rb +183 -0
  144. data/spec/spec_helper.rb +74 -0
  145. data/spec/support/opal.rb +8 -0
  146. data/spec/support/opal.rb.erb +14 -0
  147. data/spec/support/parslet_matchers.rb +96 -0
  148. metadata +240 -0
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ describe Parslet::Scope do
4
+ let(:scope) { described_class.new }
5
+
6
+ describe 'simple store/retrieve' do
7
+ before(:each) { scope[:foo] = :bar }
8
+ it "allows storing objects" do
9
+ scope[:obj] = 42
10
+ end
11
+ it "raises on access of empty slots" do
12
+ expect {
13
+ scope[:empty]
14
+ }.to raise_error(Parslet::Scope::NotFound)
15
+ end
16
+ it "allows retrieval of stored values" do
17
+ scope[:foo].should == :bar
18
+ end
19
+ end
20
+
21
+ describe 'scoping' do
22
+ before(:each) { scope[:depth] = 1 }
23
+ before(:each) { scope.push }
24
+
25
+ let(:depth) { scope[:depth] }
26
+ subject { depth }
27
+
28
+ it { should == 1 }
29
+ describe 'after a push' do
30
+ before(:each) { scope.push }
31
+ it { should == 1 }
32
+
33
+ describe 'and reassign' do
34
+ before(:each) { scope[:depth] = 2 }
35
+
36
+ it { should == 2 }
37
+
38
+ describe 'and a pop' do
39
+ before(:each) { scope.pop }
40
+ it { should == 1 }
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,186 @@
1
+ require 'spec_helper'
2
+
3
+ describe Parslet::Slice do
4
+ def cslice(string, offset, cache = nil)
5
+ described_class.new(
6
+ Parslet::Position.new(string, offset),
7
+ string, cache
8
+ )
9
+ end
10
+
11
+ describe 'construction' do
12
+ it 'constructs from an offset and a string' do
13
+ cslice('foobar', 40)
14
+ end
15
+ end
16
+
17
+ context "('foobar', 40, 'foobar')" do
18
+ let(:slice) { cslice('foobar', 40) }
19
+
20
+ describe 'comparison' do
21
+ it 'is equal to other slices with the same attributes' do
22
+ other = cslice('foobar', 40)
23
+ slice.should == other
24
+ other.should == slice
25
+ end
26
+
27
+ it 'is equal to other slices (offset is irrelevant for comparison)' do
28
+ other = cslice('foobar', 41)
29
+ slice.should == other
30
+ other.should == slice
31
+ end
32
+
33
+ it 'is equal to a string with the same content' do
34
+ slice.should == 'foobar'
35
+ end
36
+
37
+ it 'is equal to a string (inversed operands)' do
38
+ 'foobar'.should == slice
39
+ end
40
+
41
+ it 'is not equal to a string' do
42
+ slice.should_not equal('foobar')
43
+ end
44
+
45
+ it 'is not eql to a string' do
46
+ # For Opal we have redefined inspect to return the string itself
47
+ skip if RUBY_ENGINE == 'opal'
48
+
49
+ slice.should_not eql('foobar')
50
+ end
51
+
52
+ it 'does not hash to the same number' do
53
+ # In Opal, the hash of a string is the same as the string itself when we redefined inspect
54
+ skip if RUBY_ENGINE == 'opal'
55
+ slice.hash.should_not == 'foobar'.hash
56
+ end
57
+ end
58
+
59
+ describe 'offset' do
60
+ it 'returns the associated offset' do
61
+ slice.offset.should == 6
62
+ end
63
+
64
+ it 'fails to return a line and column' do
65
+ lambda {
66
+ slice.line_and_column
67
+ }.should raise_error(ArgumentError)
68
+ end
69
+
70
+ context 'when constructed with a source' do
71
+ let(:cache) { double(:cache, line_and_column: [13, 14]) }
72
+ let(:slice) { cslice('foobar', 40, cache) }
73
+
74
+ it 'returns proper line and column' do
75
+ slice.line_and_column.should == [13, 14]
76
+ end
77
+ end
78
+ end
79
+
80
+ describe 'string methods' do
81
+ describe 'matching' do
82
+ it 'matches as a string would' do
83
+ slice.should match(/bar/)
84
+ slice.should match(/foo/)
85
+
86
+ md = slice.match(/f(o)o/)
87
+ md.captures.first.should == 'o'
88
+ end
89
+ end
90
+
91
+ describe '<- #size' do
92
+ subject { slice.size }
93
+
94
+ it { is_expected.to eq(6) }
95
+ end
96
+
97
+ describe '<- #length' do
98
+ subject { slice.length }
99
+
100
+ it { is_expected.to eq(6) }
101
+ end
102
+
103
+ describe '<- #+' do
104
+ subject { slice + other }
105
+
106
+ let(:other) { cslice('baz', 10) }
107
+
108
+ it 'concats like string does' do
109
+ subject.size.should == 9
110
+ subject.should == 'foobarbaz'
111
+ subject.offset.should == 6
112
+ end
113
+ end
114
+ end
115
+
116
+ describe 'conversion' do
117
+ describe '<- #to_slice' do
118
+ it 'returns self' do
119
+ slice.to_slice.should eq(slice)
120
+ end
121
+ end
122
+
123
+ describe '<- #to_sym' do
124
+ it 'returns :foobar' do
125
+ slice.to_sym.should == :foobar
126
+ end
127
+ end
128
+
129
+ describe 'cast to Float' do
130
+ it 'returns a float' do
131
+ Float(cslice('1.345', 11)).should == 1.345
132
+ end
133
+ end
134
+
135
+ describe 'cast to Integer' do
136
+ it 'casts to integer as a string would' do
137
+ s = cslice('1234', 40)
138
+ Integer(s).should == 1234
139
+ s.to_i.should == 1234
140
+ end
141
+
142
+ it 'fails when Integer would fail on a string' do
143
+ -> { Integer(slice.to_s) }.should raise_error(ArgumentError, /invalid value/)
144
+ end
145
+
146
+ it 'turns into zero when a string would' do
147
+ slice.to_i.should == 0
148
+ end
149
+ end
150
+ end
151
+
152
+ describe 'inspection and string conversion' do
153
+ describe '#inspect' do
154
+ subject { slice.inspect }
155
+
156
+
157
+ it {
158
+ # For Opal we have redefined inspect to return the string itself
159
+ skip if RUBY_ENGINE == 'opal'
160
+
161
+ is_expected.to eq('"foobar"@6')
162
+ }
163
+ end
164
+
165
+ describe '#to_s' do
166
+ subject { slice.to_s }
167
+
168
+ it { is_expected.to eq('foobar') }
169
+ end
170
+ end
171
+
172
+ describe 'serializability' do
173
+ it 'serializes' do
174
+ Marshal.dump(slice)
175
+ end
176
+
177
+ context 'when storing a line cache' do
178
+ let(:slice) { cslice('foobar', 40, Parslet::Source::LineCache.new) }
179
+
180
+ it 'serializes' do
181
+ Marshal.dump(slice)
182
+ end
183
+ end
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,74 @@
1
+ require 'spec_helper'
2
+
3
+ describe Parslet::Source::RangeSearch do
4
+ describe "<- #lbound" do
5
+ context "for a simple array" do
6
+ let(:ary) { [10, 20, 30, 40, 50] }
7
+ before(:each) { ary.extend Parslet::Source::RangeSearch }
8
+
9
+ it "should return correct answers for numbers not in the array" do
10
+ ary.lbound(5).should == 0
11
+ ary.lbound(15).should == 1
12
+ ary.lbound(25).should == 2
13
+ ary.lbound(35).should == 3
14
+ ary.lbound(45).should == 4
15
+ end
16
+ it "should return correct answers for numbers in the array" do
17
+ ary.lbound(10).should == 1
18
+ ary.lbound(20).should == 2
19
+ ary.lbound(30).should == 3
20
+ ary.lbound(40).should == 4
21
+ end
22
+ it "should cover right edge case" do
23
+ ary.lbound(50).should be_nil
24
+ ary.lbound(51).should be_nil
25
+ end
26
+ it "should cover left edge case" do
27
+ ary.lbound(0).should == 0
28
+ end
29
+ end
30
+ context "for an empty array" do
31
+ let(:ary) { [] }
32
+ before(:each) { ary.extend Parslet::Source::RangeSearch }
33
+
34
+ it "should return nil" do
35
+ ary.lbound(1).should be_nil
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ describe Parslet::Source::LineCache do
42
+ describe "<- scan_for_line_endings" do
43
+ context "calculating the line_and_columns" do
44
+ let(:str) { "foo\nbar\nbazd" }
45
+
46
+ it "should return the first line if we have no line ends" do
47
+ subject.scan_for_line_endings(0, nil)
48
+ subject.line_and_column(3).should == [1, 4]
49
+
50
+ subject.scan_for_line_endings(0, "")
51
+ subject.line_and_column(5).should == [1, 6]
52
+ end
53
+
54
+ it "should find the right line starting from pos 0" do
55
+ subject.scan_for_line_endings(0, str)
56
+ subject.line_and_column(5).should == [2, 2]
57
+ subject.line_and_column(9).should == [3, 2]
58
+ end
59
+
60
+ it "should find the right line starting from pos 5" do
61
+ subject.scan_for_line_endings(5, str)
62
+ subject.line_and_column(11).should == [2, 3]
63
+ end
64
+
65
+ it "should find the right line if scannning the string multiple times" do
66
+ subject.scan_for_line_endings(0, str)
67
+ subject.scan_for_line_endings(0, "#{str}\nthe quick\nbrown fox")
68
+ subject.line_and_column(10).should == [3,3]
69
+ subject.line_and_column(24).should == [5,2]
70
+ end
71
+ end
72
+ end
73
+ end
74
+
@@ -0,0 +1,210 @@
1
+ require 'spec_helper'
2
+
3
+ describe Parslet::Source do
4
+ describe 'using simple input' do
5
+ let(:str) { 'a' * 100 + "\n" + 'a' * 100 + "\n" }
6
+ let(:source) { described_class.new(str) }
7
+
8
+ describe '<- #read(n)' do
9
+ it 'does not raise error when the return value is nil' do
10
+ described_class.new('').consume(1)
11
+ end
12
+
13
+ it "returns 100 'a's when reading 100 chars" do
14
+ source.consume(100).should == 'a' * 100
15
+ end
16
+ end
17
+
18
+ describe '<- #chars_left' do
19
+ subject { source.chars_left }
20
+
21
+ it { is_expected.to eq(202) }
22
+
23
+ context 'after depleting the source' do
24
+ before { source.consume(10_000) }
25
+
26
+ it { is_expected.to eq(0) }
27
+ end
28
+ end
29
+
30
+ describe '<- #pos' do
31
+ subject { source.pos.charpos }
32
+
33
+ it { is_expected.to eq(0) }
34
+
35
+ context 'after reading a few bytes' do
36
+ it 'stills be correct' do
37
+ pos = 0
38
+ 10.times do
39
+ pos += (n = rand(1..10))
40
+ source.consume(n)
41
+
42
+ source.pos.charpos.should == pos
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ describe '<- #pos=(n)' do
49
+ subject { source.pos.charpos }
50
+
51
+ 10.times do
52
+ pos = rand(200)
53
+ context "setting position #{pos}" do
54
+ before { source.bytepos = pos }
55
+
56
+ it { is_expected.to eq(pos) }
57
+ end
58
+ end
59
+ end
60
+
61
+ describe '#chars_until' do
62
+ it 'returns 100 chars before line end' do
63
+ source.chars_until("\n").should == 100
64
+ end
65
+ end
66
+
67
+ describe '<- #column & #line' do
68
+ subject { source.line_and_column }
69
+
70
+ it { is_expected.to eq([1, 1]) }
71
+
72
+ context 'on the first line' do
73
+ it 'increases column with every read' do
74
+ 10.times do |i|
75
+ source.line_and_column.last.should == 1 + i
76
+ source.consume(1)
77
+ end
78
+ end
79
+ end
80
+
81
+ context 'on the second line' do
82
+ before { source.consume(101) }
83
+
84
+ it { is_expected.to eq([2, 1]) }
85
+ end
86
+
87
+ context 'after reading everything' do
88
+ before { source.consume(10_000) }
89
+
90
+ context 'when seeking to 9' do
91
+ before { source.bytepos = 9 }
92
+
93
+ it { is_expected.to eq([1, 10]) }
94
+ end
95
+
96
+ context 'when seeking to 100' do
97
+ before { source.bytepos = 100 }
98
+
99
+ it { is_expected.to eq([1, 101]) }
100
+ end
101
+
102
+ context 'when seeking to 101' do
103
+ before { source.bytepos = 101 }
104
+
105
+ it { is_expected.to eq([2, 1]) }
106
+ end
107
+
108
+ context 'when seeking to 102' do
109
+ before { source.bytepos = 102 }
110
+
111
+ it { is_expected.to eq([2, 2]) }
112
+ end
113
+
114
+ context 'when seeking beyond eof' do
115
+ it 'does not throw an error' do
116
+ source.bytepos = 1000
117
+ end
118
+ end
119
+ end
120
+
121
+ context 'reading char by char, storing the results' do
122
+ attr_reader :results
123
+
124
+ before do
125
+ @results = {}
126
+ while source.chars_left > 0
127
+ pos = source.pos.charpos
128
+ @results[pos] = source.line_and_column
129
+ source.consume(1)
130
+ end
131
+
132
+ @results.entries.size.should == 202
133
+ @results
134
+ end
135
+
136
+ context 'when using pos argument' do
137
+ it 'returns the same results' do
138
+ results.each do |pos, result|
139
+ source.line_and_column(pos).should == result
140
+ end
141
+ end
142
+ end
143
+
144
+ it 'gives the same results when seeking' do
145
+ results.each do |pos, result|
146
+ source.bytepos = pos
147
+ source.line_and_column.should == result
148
+ end
149
+ end
150
+
151
+ it 'gives the same results when reading' do
152
+ cur = source.bytepos = 0
153
+ while source.chars_left > 0
154
+ source.line_and_column.should == results[cur]
155
+ cur += 1
156
+ source.consume(1)
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end
162
+
163
+ describe 'reading encoded input' do
164
+ let(:source) { described_class.new('éö変わる') }
165
+
166
+ def r(str)
167
+ Regexp.new(Regexp.escape(str))
168
+ end
169
+
170
+ it 'reads characters, not bytes' do
171
+ source.should match(r('é'))
172
+ source.consume(1)
173
+ source.pos.charpos.should == 1
174
+
175
+ # TODO This needs to be fixed in code with Opal
176
+ if RUBY_ENGINE == 'opal'
177
+ skip "Opal does not support byte positions and char positions correctly for multi-byte characters"
178
+ end
179
+
180
+ source.bytepos.should == if RUBY_ENGINE == 'opal'
181
+ # In Opal/JavaScript, string indexing is character-based, not byte-based
182
+ 1
183
+ else
184
+ # In Ruby, multi-byte characters have different byte positions
185
+ 2
186
+ end
187
+
188
+ source.should match(r('ö'))
189
+ source.consume(1)
190
+ source.pos.charpos.should == if RUBY_ENGINE == 'opal'
191
+ 1
192
+ else
193
+ 2
194
+ end
195
+
196
+ source.bytepos.should == if RUBY_ENGINE == 'opal'
197
+ 2
198
+ else
199
+ 4
200
+ end
201
+
202
+ source.should match(r('変'))
203
+ source.consume(1)
204
+
205
+ source.consume(2)
206
+ source.chars_left.should == 0
207
+ source.chars_left.should == 0
208
+ end
209
+ end
210
+ end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+
3
+ describe Parslet::Context do
4
+ def context(*args)
5
+ described_class.new(*args)
6
+ end
7
+
8
+ it "binds hash keys as variable like things" do
9
+ context(:a => 'value').instance_eval { a }.
10
+ should == 'value'
11
+ end
12
+ it "one contexts variables aren't the next ones" do
13
+ ca = context(:a => 'b')
14
+ cb = context(:b => 'c')
15
+
16
+ ca.methods.should_not include(:b)
17
+ cb.methods.should_not include(:a)
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
+ expect(obj.respond_to?(:a)).to be_truthy
25
+ end
26
+ it 'includes :a in #methods' do
27
+ expect(obj.methods).to include(:a)
28
+ end
29
+ it 'allows inspection' do
30
+ expect(obj.inspect).to match(/@a=1/)
31
+ end
32
+ it 'allows conversion to string' do
33
+ expect(obj.to_s).to 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
+ expect(obj.respond_to?(:foo)).to be_truthy
47
+ end
48
+ it 'includes :foo also in methods' do
49
+ expect(obj.methods).to include(:foo)
50
+ end
51
+ it 'allows calling #foo' do
52
+ expect(obj.foo).to eq('foo')
53
+ end
54
+ end
55
+ end
56
+ end