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.
- checksums.yaml +7 -0
- data/HISTORY.txt +284 -0
- data/LICENSE +23 -0
- data/README.adoc +454 -0
- data/Rakefile +71 -0
- data/lib/parslet/accelerator/application.rb +62 -0
- data/lib/parslet/accelerator/engine.rb +112 -0
- data/lib/parslet/accelerator.rb +162 -0
- data/lib/parslet/atoms/alternative.rb +53 -0
- data/lib/parslet/atoms/base.rb +157 -0
- data/lib/parslet/atoms/can_flatten.rb +137 -0
- data/lib/parslet/atoms/capture.rb +38 -0
- data/lib/parslet/atoms/context.rb +103 -0
- data/lib/parslet/atoms/dsl.rb +112 -0
- data/lib/parslet/atoms/dynamic.rb +32 -0
- data/lib/parslet/atoms/entity.rb +45 -0
- data/lib/parslet/atoms/ignored.rb +26 -0
- data/lib/parslet/atoms/infix.rb +115 -0
- data/lib/parslet/atoms/lookahead.rb +52 -0
- data/lib/parslet/atoms/named.rb +32 -0
- data/lib/parslet/atoms/re.rb +41 -0
- data/lib/parslet/atoms/repetition.rb +87 -0
- data/lib/parslet/atoms/scope.rb +26 -0
- data/lib/parslet/atoms/sequence.rb +48 -0
- data/lib/parslet/atoms/str.rb +42 -0
- data/lib/parslet/atoms/visitor.rb +89 -0
- data/lib/parslet/atoms.rb +34 -0
- data/lib/parslet/cause.rb +101 -0
- data/lib/parslet/context.rb +21 -0
- data/lib/parslet/convenience.rb +33 -0
- data/lib/parslet/error_reporter/contextual.rb +120 -0
- data/lib/parslet/error_reporter/deepest.rb +100 -0
- data/lib/parslet/error_reporter/tree.rb +63 -0
- data/lib/parslet/error_reporter.rb +8 -0
- data/lib/parslet/export.rb +163 -0
- data/lib/parslet/expression/treetop.rb +92 -0
- data/lib/parslet/expression.rb +51 -0
- data/lib/parslet/graphviz.rb +97 -0
- data/lib/parslet/parser.rb +68 -0
- data/lib/parslet/pattern/binding.rb +49 -0
- data/lib/parslet/pattern.rb +113 -0
- data/lib/parslet/position.rb +21 -0
- data/lib/parslet/rig/rspec.rb +52 -0
- data/lib/parslet/scope.rb +42 -0
- data/lib/parslet/slice.rb +105 -0
- data/lib/parslet/source/line_cache.rb +99 -0
- data/lib/parslet/source.rb +96 -0
- data/lib/parslet/transform.rb +265 -0
- data/lib/parslet/version.rb +5 -0
- data/lib/parslet.rb +314 -0
- data/plurimath-parslet.gemspec +42 -0
- data/spec/acceptance/infix_parser_spec.rb +145 -0
- data/spec/acceptance/mixing_parsers_spec.rb +74 -0
- data/spec/acceptance/regression_spec.rb +329 -0
- data/spec/acceptance/repetition_and_maybe_spec.rb +44 -0
- data/spec/acceptance/unconsumed_input_spec.rb +21 -0
- data/spec/examples/boolean_algebra_spec.rb +257 -0
- data/spec/examples/calc_spec.rb +278 -0
- data/spec/examples/capture_spec.rb +137 -0
- data/spec/examples/comments_spec.rb +186 -0
- data/spec/examples/deepest_errors_spec.rb +420 -0
- data/spec/examples/documentation_spec.rb +205 -0
- data/spec/examples/email_parser_spec.rb +275 -0
- data/spec/examples/empty_spec.rb +37 -0
- data/spec/examples/erb_spec.rb +482 -0
- data/spec/examples/ip_address_spec.rb +153 -0
- data/spec/examples/json_spec.rb +413 -0
- data/spec/examples/local_spec.rb +302 -0
- data/spec/examples/mathn_spec.rb +151 -0
- data/spec/examples/minilisp_spec.rb +492 -0
- data/spec/examples/modularity_spec.rb +340 -0
- data/spec/examples/nested_errors_spec.rb +322 -0
- data/spec/examples/optimized_erb_spec.rb +299 -0
- data/spec/examples/parens_spec.rb +239 -0
- data/spec/examples/prec_calc_spec.rb +525 -0
- data/spec/examples/readme_spec.rb +228 -0
- data/spec/examples/scopes_spec.rb +187 -0
- data/spec/examples/seasons_spec.rb +196 -0
- data/spec/examples/sentence_spec.rb +119 -0
- data/spec/examples/simple_xml_spec.rb +250 -0
- data/spec/examples/string_parser_spec.rb +407 -0
- data/spec/fixtures/examples/boolean_algebra.rb +62 -0
- data/spec/fixtures/examples/calc.rb +86 -0
- data/spec/fixtures/examples/capture.rb +36 -0
- data/spec/fixtures/examples/comments.rb +22 -0
- data/spec/fixtures/examples/deepest_errors.rb +99 -0
- data/spec/fixtures/examples/documentation.rb +32 -0
- data/spec/fixtures/examples/email_parser.rb +42 -0
- data/spec/fixtures/examples/empty.rb +10 -0
- data/spec/fixtures/examples/erb.rb +39 -0
- data/spec/fixtures/examples/ip_address.rb +103 -0
- data/spec/fixtures/examples/json.rb +107 -0
- data/spec/fixtures/examples/local.rb +60 -0
- data/spec/fixtures/examples/mathn.rb +47 -0
- data/spec/fixtures/examples/minilisp.rb +75 -0
- data/spec/fixtures/examples/modularity.rb +60 -0
- data/spec/fixtures/examples/nested_errors.rb +95 -0
- data/spec/fixtures/examples/optimized_erb.rb +105 -0
- data/spec/fixtures/examples/parens.rb +25 -0
- data/spec/fixtures/examples/prec_calc.rb +71 -0
- data/spec/fixtures/examples/readme.rb +59 -0
- data/spec/fixtures/examples/scopes.rb +43 -0
- data/spec/fixtures/examples/seasons.rb +40 -0
- data/spec/fixtures/examples/sentence.rb +18 -0
- data/spec/fixtures/examples/simple_xml.rb +51 -0
- data/spec/fixtures/examples/string_parser.rb +77 -0
- data/spec/parslet/atom_results_spec.rb +39 -0
- data/spec/parslet/atoms/alternative_spec.rb +26 -0
- data/spec/parslet/atoms/base_spec.rb +127 -0
- data/spec/parslet/atoms/capture_spec.rb +21 -0
- data/spec/parslet/atoms/combinations_spec.rb +5 -0
- data/spec/parslet/atoms/dsl_spec.rb +7 -0
- data/spec/parslet/atoms/entity_spec.rb +77 -0
- data/spec/parslet/atoms/ignored_spec.rb +15 -0
- data/spec/parslet/atoms/infix_spec.rb +5 -0
- data/spec/parslet/atoms/lookahead_spec.rb +22 -0
- data/spec/parslet/atoms/named_spec.rb +4 -0
- data/spec/parslet/atoms/re_spec.rb +14 -0
- data/spec/parslet/atoms/repetition_spec.rb +24 -0
- data/spec/parslet/atoms/scope_spec.rb +26 -0
- data/spec/parslet/atoms/sequence_spec.rb +28 -0
- data/spec/parslet/atoms/str_spec.rb +15 -0
- data/spec/parslet/atoms/visitor_spec.rb +101 -0
- data/spec/parslet/atoms_spec.rb +488 -0
- data/spec/parslet/convenience_spec.rb +54 -0
- data/spec/parslet/error_reporter/contextual_spec.rb +118 -0
- data/spec/parslet/error_reporter/deepest_spec.rb +82 -0
- data/spec/parslet/error_reporter/tree_spec.rb +7 -0
- data/spec/parslet/export_spec.rb +40 -0
- data/spec/parslet/expression/treetop_spec.rb +74 -0
- data/spec/parslet/minilisp.citrus +29 -0
- data/spec/parslet/minilisp.tt +29 -0
- data/spec/parslet/parser_spec.rb +36 -0
- data/spec/parslet/parslet_spec.rb +38 -0
- data/spec/parslet/pattern_spec.rb +272 -0
- data/spec/parslet/position_spec.rb +14 -0
- data/spec/parslet/rig/rspec_spec.rb +54 -0
- data/spec/parslet/scope_spec.rb +45 -0
- data/spec/parslet/slice_spec.rb +186 -0
- data/spec/parslet/source/line_cache_spec.rb +74 -0
- data/spec/parslet/source_spec.rb +210 -0
- data/spec/parslet/transform/context_spec.rb +56 -0
- data/spec/parslet/transform_spec.rb +183 -0
- data/spec/spec_helper.rb +74 -0
- data/spec/support/opal.rb +8 -0
- data/spec/support/opal.rb.erb +14 -0
- data/spec/support/parslet_matchers.rb +96 -0
- 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
|