sequitur 0.1.23 → 0.1.24
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 +4 -4
- data/.rubocop.yml +11 -437
- data/CHANGELOG.md +3 -0
- data/LICENSE.txt +1 -1
- data/Rakefile +0 -2
- data/examples/integer_sample.rb +0 -1
- data/examples/porridge.rb +9 -9
- data/examples/word_sample.rb +4 -5
- data/lib/sequitur/constants.rb +4 -1
- data/lib/sequitur/digram.rb +2 -2
- data/lib/sequitur/dynamic_grammar.rb +3 -4
- data/lib/sequitur/formatter/base_formatter.rb +1 -1
- data/lib/sequitur/formatter/base_text.rb +3 -7
- data/lib/sequitur/formatter/debug.rb +0 -1
- data/lib/sequitur/grammar_visitor.rb +1 -1
- data/lib/sequitur/production.rb +200 -205
- data/lib/sequitur/production_ref.rb +9 -12
- data/lib/sequitur/sequitur_grammar.rb +135 -137
- data/lib/sequitur/symbol_sequence.rb +24 -27
- data/lib/sequitur.rb +4 -5
- data/spec/sequitur/digram_spec.rb +13 -12
- data/spec/sequitur/dynamic_grammar_spec.rb +5 -11
- data/spec/sequitur/formatter/base_text_spec.rb +70 -72
- data/spec/sequitur/formatter/debug_spec.rb +90 -92
- data/spec/sequitur/grammar_visitor_spec.rb +70 -71
- data/spec/sequitur/production_ref_spec.rb +92 -92
- data/spec/sequitur/production_spec.rb +30 -34
- data/spec/sequitur/sequitur_grammar_spec.rb +47 -46
- data/spec/sequitur/symbol_sequence_spec.rb +102 -105
- data/spec/spec_helper.rb +0 -1
- metadata +4 -5
- data/.travis.yml +0 -29
@@ -7,98 +7,98 @@ require_relative '../../lib/sequitur/production'
|
|
7
7
|
require_relative '../../lib/sequitur/production_ref'
|
8
8
|
|
9
9
|
module Sequitur # Re-open the module to get rid of qualified names
|
10
|
-
describe ProductionRef do
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
end # describe
|
10
|
+
describe ProductionRef do
|
11
|
+
let(:target) { Production.new }
|
12
|
+
let(:another_target) { Production.new }
|
13
|
+
|
14
|
+
subject { ProductionRef.new(target) }
|
15
|
+
|
16
|
+
context 'Creation & initialization:' do
|
17
|
+
it 'should be created with a production argument' do
|
18
|
+
expect { ProductionRef.new(target) }.not_to raise_error
|
19
|
+
expect(target.refcount).to eq(1)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should clone with reference count incrementing' do
|
23
|
+
expect(target.refcount).to eq(0)
|
24
|
+
expect(subject.production.refcount).to eq(1)
|
25
|
+
klone = subject.clone
|
26
|
+
expect(klone.production.refcount).to eq(2)
|
27
|
+
duplicate = subject.dup
|
28
|
+
expect(duplicate.production.refcount).to eq(3)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should know its referenced production' do
|
32
|
+
instance = ProductionRef.new(target)
|
33
|
+
expect(instance.production).to eq(target)
|
34
|
+
end
|
35
|
+
end # context
|
36
|
+
|
37
|
+
context 'Provided services:' do
|
38
|
+
it 'should render its referenced production' do
|
39
|
+
expect(subject.to_s).to eq(target.object_id.to_s)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should unbind itself from its production' do
|
43
|
+
expect(target.refcount).to eq(0)
|
44
|
+
expect(subject).not_to be_unbound
|
45
|
+
expect(target.refcount).to eq(1)
|
46
|
+
subject.unbind
|
47
|
+
expect(target.refcount).to eq(0)
|
48
|
+
expect(subject.production).to be_nil
|
49
|
+
expect(subject).to be_unbound
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should bind to a production' do
|
53
|
+
expect(target.refcount).to eq(0)
|
54
|
+
|
55
|
+
expect(subject).not_to be_unbound
|
56
|
+
expect(target.refcount).to eq(1)
|
57
|
+
|
58
|
+
# Case: bind again to same production
|
59
|
+
expect { subject.bind_to(target) }.not_to raise_error
|
60
|
+
expect(target.refcount).to eq(1)
|
61
|
+
|
62
|
+
# Case: bind to another production
|
63
|
+
expect(another_target.refcount).to eq(0)
|
64
|
+
subject.bind_to(another_target)
|
65
|
+
expect(target.refcount).to eq(0)
|
66
|
+
expect(another_target.refcount).to eq(1)
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'should complain when binding to something else than production' do
|
70
|
+
subject.bind_to(target)
|
71
|
+
msg = 'Illegal production type String'
|
72
|
+
expect { subject.bind_to('WRONG') }.to raise_error(StandardError, msg)
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'should compare to other production (reference)' do
|
76
|
+
same = ProductionRef.new(target)
|
77
|
+
expect(subject).to eq(subject) # Strict identity
|
78
|
+
expect(subject).to eq(same) # 2 references pointing to same production
|
79
|
+
expect(subject).to eq(target)
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should return the hash value of its production' do
|
83
|
+
expectation = target.hash
|
84
|
+
expect(subject.hash).to eq(expectation)
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'should complain when requested for a hash and unbound' do
|
88
|
+
subject.unbind
|
89
|
+
expect { subject.hash }.to raise_error(StandardError)
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'should accept a visitor' do
|
93
|
+
# Use a mock visitor
|
94
|
+
fake = double('fake_visitor')
|
95
|
+
|
96
|
+
# Visitor should receive a visit message
|
97
|
+
expect(fake).to receive(:visit_prod_ref).once
|
98
|
+
expect { subject.accept(fake) }.not_to raise_error
|
99
|
+
end
|
100
|
+
end # context
|
101
|
+
end # describe
|
102
102
|
end # module
|
103
103
|
|
104
104
|
# End of file
|
@@ -5,22 +5,26 @@ require_relative '../spec_helper'
|
|
5
5
|
# Load the class under test
|
6
6
|
require_relative '../../lib/sequitur/production'
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
describe Sequitur::Production do
|
9
|
+
# Factory method. Returns a Sequitur::Production
|
10
|
+
def make_production
|
11
|
+
Sequitur::Production.new
|
12
|
+
end
|
13
|
+
|
10
14
|
# Helper method: convert list of digrams into an array
|
11
15
|
# of symbol couples.
|
12
|
-
def to_symbols(
|
13
|
-
|
16
|
+
def to_symbols(digrams)
|
17
|
+
digrams.map(&:symbols)
|
14
18
|
end
|
15
19
|
|
16
20
|
let(:p_a) do
|
17
|
-
|
18
|
-
|
19
|
-
|
21
|
+
instance = make_production
|
22
|
+
instance.append_symbol(:a)
|
23
|
+
instance
|
20
24
|
end
|
21
25
|
|
22
26
|
let(:p_bc) do
|
23
|
-
instance =
|
27
|
+
instance = make_production
|
24
28
|
instance.append_symbol('b')
|
25
29
|
instance.append_symbol('c')
|
26
30
|
instance
|
@@ -28,7 +32,7 @@ describe Production do
|
|
28
32
|
|
29
33
|
context 'Creation & initialization:' do
|
30
34
|
it 'should be created without argument' do
|
31
|
-
expect {
|
35
|
+
expect { make_production }.not_to raise_error
|
32
36
|
end
|
33
37
|
|
34
38
|
it 'should not referenced yet' do
|
@@ -52,11 +56,11 @@ describe Production do
|
|
52
56
|
end
|
53
57
|
|
54
58
|
it 'should compare to a production reference' do
|
55
|
-
ref_a = ProductionRef.new(p_a)
|
59
|
+
ref_a = Sequitur::ProductionRef.new(p_a)
|
56
60
|
expect(p_a).to eq(ref_a)
|
57
61
|
expect(p_bc).not_to eq(ref_a)
|
58
62
|
|
59
|
-
ref_bc = ProductionRef.new(p_bc)
|
63
|
+
ref_bc = Sequitur::ProductionRef.new(p_bc)
|
60
64
|
expect(p_a).not_to eq(ref_bc)
|
61
65
|
expect(p_bc).to eq(ref_bc)
|
62
66
|
end
|
@@ -78,13 +82,11 @@ describe Production do
|
|
78
82
|
expect(subject.references).to eq([p_a])
|
79
83
|
expect(subject.references_of(p_a).map(&:production)).to eq([p_a])
|
80
84
|
|
81
|
-
|
82
85
|
# Case 3: production with repeated references
|
83
86
|
subject.append_symbol(p_a) # second time
|
84
87
|
expect(subject.references).to eq([p_a, p_a])
|
85
88
|
expect(subject.references_of(p_a).map(&:production)).to eq([p_a, p_a])
|
86
89
|
|
87
|
-
|
88
90
|
# Case 4: production with multiple distinct references
|
89
91
|
subject.append_symbol(p_bc)
|
90
92
|
expect(subject.references).to eq([p_a, p_a, p_bc])
|
@@ -138,7 +140,7 @@ describe Production do
|
|
138
140
|
|
139
141
|
it 'should append a production ref in its rhs' do
|
140
142
|
# Side-effect: refcount of production to append is incremented
|
141
|
-
ref_a = ProductionRef.new(p_a)
|
143
|
+
ref_a = Sequitur::ProductionRef.new(p_a)
|
142
144
|
expect(p_a.refcount).to be(1)
|
143
145
|
|
144
146
|
input = [ref_a, :b, :c, :d, ref_a] # ref_a appears twice
|
@@ -157,7 +159,7 @@ describe Production do
|
|
157
159
|
|
158
160
|
it 'should complain when appending ref to nil production' do
|
159
161
|
# Side-effect: refcount of production to append is incremented
|
160
|
-
ref_a = ProductionRef.new(p_a)
|
162
|
+
ref_a = Sequitur::ProductionRef.new(p_a)
|
161
163
|
expect(p_a.refcount).to be(1)
|
162
164
|
|
163
165
|
# Unbind the reference
|
@@ -167,7 +169,6 @@ describe Production do
|
|
167
169
|
end
|
168
170
|
end # context
|
169
171
|
|
170
|
-
|
171
172
|
context 'Text representation of a production rule:' do
|
172
173
|
it 'should emit minimal text when empty' do
|
173
174
|
expectation = "#{subject.object_id} : ."
|
@@ -175,7 +176,7 @@ describe Production do
|
|
175
176
|
end
|
176
177
|
|
177
178
|
it 'should emit its text representation' do
|
178
|
-
instance =
|
179
|
+
instance = make_production
|
179
180
|
symbols = [:a, :b, 'c', :d, :e, 1000, instance]
|
180
181
|
symbols.each { |symb| subject.append_symbol(symb) }
|
181
182
|
expectation = +"#{subject.object_id} : "
|
@@ -204,17 +205,17 @@ describe Production do
|
|
204
205
|
|
205
206
|
it 'should detect any repetition pattern' do
|
206
207
|
# Positive cases
|
207
|
-
cases = %w
|
208
|
+
cases = %w[abab abcdab abcdcd abcdefcd]
|
208
209
|
cases.each do |word|
|
209
|
-
instance =
|
210
|
+
instance = make_production
|
210
211
|
word.each_char { |symb| instance.append_symbol(symb) }
|
211
212
|
expect(instance.repeated_digram?).to be_truthy
|
212
213
|
end
|
213
214
|
|
214
215
|
# Negative cases
|
215
|
-
cases = %w
|
216
|
+
cases = %w[abc abb abba abcdef]
|
216
217
|
cases.each do |word|
|
217
|
-
instance =
|
218
|
+
instance = make_production
|
218
219
|
word.each_char { |symb| instance.append_symbol(symb) }
|
219
220
|
expect(instance.repeated_digram?).to be_falsey
|
220
221
|
end
|
@@ -228,9 +229,8 @@ describe Production do
|
|
228
229
|
expect(p_bc.refcount).to eq(0)
|
229
230
|
end
|
230
231
|
|
231
|
-
|
232
232
|
it 'should replace two-symbol sequence' do
|
233
|
-
%w
|
233
|
+
%w[a b c d e b c e].each { |symb| subject.append_symbol(symb) }
|
234
234
|
p_bc_before = p_bc.to_string
|
235
235
|
subject.reduce_step(p_bc)
|
236
236
|
|
@@ -240,9 +240,8 @@ describe Production do
|
|
240
240
|
expect(p_bc.to_string).to eq(p_bc_before)
|
241
241
|
end
|
242
242
|
|
243
|
-
|
244
243
|
it 'should replace a starting two-symbol sequence' do
|
245
|
-
%w
|
244
|
+
%w[b c d e b c e].each { |symb| subject.append_symbol(symb) }
|
246
245
|
subject.reduce_step(p_bc)
|
247
246
|
|
248
247
|
expect(subject.rhs.size).to eq(5)
|
@@ -250,9 +249,8 @@ describe Production do
|
|
250
249
|
expect(p_bc.refcount).to eq(2)
|
251
250
|
end
|
252
251
|
|
253
|
-
|
254
252
|
it 'should replace an ending two-symbol sequence' do
|
255
|
-
%w
|
253
|
+
%w[a b c d e b c].each { |symb| subject.append_symbol(symb) }
|
256
254
|
subject.reduce_step(p_bc)
|
257
255
|
|
258
256
|
expect(subject.rhs.size).to eq(5)
|
@@ -261,7 +259,7 @@ describe Production do
|
|
261
259
|
end
|
262
260
|
|
263
261
|
it 'should replace two consecutive two-symbol sequences' do
|
264
|
-
%w
|
262
|
+
%w[a b c b c d].each { |symb| subject.append_symbol(symb) }
|
265
263
|
subject.reduce_step(p_bc)
|
266
264
|
|
267
265
|
expect(subject.rhs.size).to eq(4)
|
@@ -282,18 +280,17 @@ describe Production do
|
|
282
280
|
|
283
281
|
subject.derive_step(p_bc)
|
284
282
|
expect(subject.rhs.size).to eq(3)
|
285
|
-
expect(subject.rhs).to eq(%w
|
283
|
+
expect(subject.rhs).to eq(%w[b c d])
|
286
284
|
expect(p_bc.refcount).to eq(0)
|
287
285
|
end
|
288
286
|
|
289
|
-
|
290
287
|
it 'should replace a production at the end' do
|
291
288
|
['d', p_bc].each { |symb| subject.append_symbol(symb) }
|
292
289
|
expect(p_bc.refcount).to eq(1)
|
293
290
|
subject.derive_step(p_bc)
|
294
291
|
|
295
292
|
expect(subject.rhs.size).to eq(3)
|
296
|
-
expect(subject.rhs).to eq(%w
|
293
|
+
expect(subject.rhs).to eq(%w[d b c])
|
297
294
|
expect(p_bc.refcount).to eq(0)
|
298
295
|
end
|
299
296
|
|
@@ -302,7 +299,7 @@ describe Production do
|
|
302
299
|
subject.derive_step(p_bc)
|
303
300
|
|
304
301
|
expect(subject.rhs.size).to eq(2)
|
305
|
-
expect(subject.rhs).to eq(%w
|
302
|
+
expect(subject.rhs).to eq(%w[b c])
|
306
303
|
end
|
307
304
|
|
308
305
|
it 'should replace a production in the middle' do
|
@@ -310,7 +307,7 @@ describe Production do
|
|
310
307
|
subject.derive_step(p_bc)
|
311
308
|
|
312
309
|
expect(subject.rhs.size).to eq(4)
|
313
|
-
expect(subject.rhs).to eq(%w
|
310
|
+
expect(subject.rhs).to eq(%w[a b c d])
|
314
311
|
end
|
315
312
|
end # context
|
316
313
|
|
@@ -358,6 +355,5 @@ describe Production do
|
|
358
355
|
end
|
359
356
|
end # context
|
360
357
|
end # describe
|
361
|
-
end # module
|
362
358
|
|
363
359
|
# End of file
|
@@ -5,20 +5,24 @@ require_relative '../spec_helper'
|
|
5
5
|
# Load the class under test
|
6
6
|
require_relative '../../lib/sequitur/sequitur_grammar'
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
describe Sequitur::SequiturGrammar do
|
9
|
+
# Factory method. Returns a SequiturGrammar
|
10
|
+
def sequitur_grammar(enumerator)
|
11
|
+
Sequitur::SequiturGrammar.new(enumerator)
|
12
|
+
end
|
13
|
+
|
10
14
|
# Factory method. Returns an empty enumerator (
|
11
15
|
# i.e. without elements to iterate)
|
12
16
|
def empty_enum
|
13
|
-
|
17
|
+
[].to_enum
|
14
18
|
end
|
15
19
|
|
16
20
|
context 'Creation from an enumeration of tokens:' do
|
17
21
|
it 'could be created with an empty enumerator' do
|
18
|
-
expect {
|
22
|
+
expect { sequitur_grammar(empty_enum) }.not_to raise_error
|
19
23
|
|
20
24
|
# Creation
|
21
|
-
instance =
|
25
|
+
instance = sequitur_grammar(empty_enum)
|
22
26
|
|
23
27
|
# Initialization
|
24
28
|
expect(instance.productions.size).to eq(1)
|
@@ -28,7 +32,7 @@ describe SequiturGrammar do
|
|
28
32
|
|
29
33
|
it 'could be created with single token' do
|
30
34
|
# Creation
|
31
|
-
instance =
|
35
|
+
instance = sequitur_grammar([:a].to_enum)
|
32
36
|
|
33
37
|
# Initialization
|
34
38
|
expect(instance.productions.size).to eq(1)
|
@@ -38,7 +42,7 @@ describe SequiturGrammar do
|
|
38
42
|
|
39
43
|
it 'could be created with multiple unique tokens' do
|
40
44
|
# Creation
|
41
|
-
instance =
|
45
|
+
instance = sequitur_grammar(%i[a b c d].to_enum)
|
42
46
|
|
43
47
|
# Initialization
|
44
48
|
expect(instance.productions.size).to eq(1)
|
@@ -47,7 +51,7 @@ describe SequiturGrammar do
|
|
47
51
|
end
|
48
52
|
|
49
53
|
it 'could be created with a repeating digram' do
|
50
|
-
instance =
|
54
|
+
instance = sequitur_grammar(%i[a b a b].to_enum)
|
51
55
|
|
52
56
|
# Expectations:
|
53
57
|
# S : A A.
|
@@ -59,7 +63,7 @@ describe SequiturGrammar do
|
|
59
63
|
end
|
60
64
|
|
61
65
|
it 'should enforce the utility rule' do
|
62
|
-
instance =
|
66
|
+
instance = sequitur_grammar(%i[a b c a b c].to_enum)
|
63
67
|
|
64
68
|
# Expectations without utility rule:
|
65
69
|
# S : B B.
|
@@ -79,15 +83,14 @@ describe SequiturGrammar do
|
|
79
83
|
input = 'aaac' # This sequence raised an exception
|
80
84
|
|
81
85
|
# Creation
|
82
|
-
expect {
|
86
|
+
expect { sequitur_grammar(input.chars) }.not_to raise_error
|
83
87
|
end
|
84
88
|
|
85
|
-
|
86
89
|
it 'should cope with the example from presentation' do
|
87
90
|
input = 'bbebeebebebbebee'
|
88
91
|
|
89
92
|
# Creation
|
90
|
-
instance =
|
93
|
+
instance = sequitur_grammar(input.chars)
|
91
94
|
|
92
95
|
# Expectations:
|
93
96
|
# S: P3 P2 P3
|
@@ -97,7 +100,7 @@ describe SequiturGrammar do
|
|
97
100
|
expect(instance.productions.size).to eq(4)
|
98
101
|
(p1, p2, p3) = instance.productions[1..3]
|
99
102
|
expect(instance.start.rhs).to eq([p3, p2, p3])
|
100
|
-
expect(p1.rhs).to eq(%w
|
103
|
+
expect(p1.rhs).to eq(%w[b e])
|
101
104
|
expect(p2.rhs).to eq([p1, p1])
|
102
105
|
expect(p3.rhs).to eq(['b', p2, 'e'])
|
103
106
|
end
|
@@ -110,7 +113,7 @@ describe SequiturGrammar do
|
|
110
113
|
input = raw_input.chars.map { |ch| "letter_#{ch}" }
|
111
114
|
|
112
115
|
# Creation
|
113
|
-
instance =
|
116
|
+
instance = sequitur_grammar(input.to_enum)
|
114
117
|
|
115
118
|
# Expectations:
|
116
119
|
# S: P3 P2 P3
|
@@ -120,7 +123,7 @@ describe SequiturGrammar do
|
|
120
123
|
expect(instance.productions.size).to eq(4)
|
121
124
|
(p1, p2, p3) = instance.productions[1..3]
|
122
125
|
expect(instance.start.rhs).to eq([p3, p2, p3])
|
123
|
-
expect(p1.rhs).to eq(%w
|
126
|
+
expect(p1.rhs).to eq(%w[letter_b letter_e])
|
124
127
|
expect(p2.rhs).to eq([p1, p1])
|
125
128
|
expect(p3.rhs).to eq(['letter_b', p2, 'letter_e'])
|
126
129
|
end
|
@@ -133,7 +136,7 @@ describe SequiturGrammar do
|
|
133
136
|
input = raw_input.chars.map(&:to_sym)
|
134
137
|
|
135
138
|
# Creation
|
136
|
-
instance =
|
139
|
+
instance = sequitur_grammar(input.to_enum)
|
137
140
|
|
138
141
|
# Expectations:
|
139
142
|
# S: P3 P2 P3
|
@@ -148,16 +151,15 @@ describe SequiturGrammar do
|
|
148
151
|
expect(p3.rhs).to eq([:b, p2, :e])
|
149
152
|
end
|
150
153
|
|
151
|
-
|
152
154
|
it 'should work with integer values as input tokens' do
|
153
155
|
# Raw input is sequence of hex digits
|
154
156
|
raw_input = 'bbebeebebebbebee'
|
155
157
|
|
156
|
-
# Convert them into
|
158
|
+
# Convert them into Integers
|
157
159
|
input = raw_input.chars.map { |ch| ch.to_i(16) }
|
158
160
|
|
159
161
|
# Creation
|
160
|
-
instance =
|
162
|
+
instance = sequitur_grammar(input.to_enum)
|
161
163
|
|
162
164
|
# Expectations:
|
163
165
|
# S: P3 P2 P3
|
@@ -174,7 +176,7 @@ describe SequiturGrammar do
|
|
174
176
|
|
175
177
|
it 'should cope with the example from sequitur.info website' do
|
176
178
|
input = 'abcabdabcabd'
|
177
|
-
instance =
|
179
|
+
instance = sequitur_grammar(input.chars)
|
178
180
|
|
179
181
|
# Expectations:
|
180
182
|
# 0 → 2 2
|
@@ -184,13 +186,13 @@ describe SequiturGrammar do
|
|
184
186
|
expect(instance.productions.size).to eq(3)
|
185
187
|
(p1, p2) = instance.productions[1..2]
|
186
188
|
expect(instance.start.rhs).to eq([p2, p2])
|
187
|
-
expect(p1.rhs).to eq(%w
|
189
|
+
expect(p1.rhs).to eq(%w[a b])
|
188
190
|
expect(p2.rhs).to eq([p1, 'c', p1, 'd'])
|
189
191
|
end
|
190
192
|
|
191
193
|
it "should cope with the example from Salomon's book" do
|
192
194
|
input = 'abcdbcabcdbc'
|
193
|
-
instance =
|
195
|
+
instance = sequitur_grammar(input.chars)
|
194
196
|
|
195
197
|
# Expectations:
|
196
198
|
# S → CC
|
@@ -200,23 +202,23 @@ describe SequiturGrammar do
|
|
200
202
|
expect(instance.productions.size).to eq(3)
|
201
203
|
(p_a, p_c) = instance.productions[1..2]
|
202
204
|
expect(instance.start.rhs).to eq([p_c, p_c])
|
203
|
-
expect(p_a.rhs).to eq(%w
|
205
|
+
expect(p_a.rhs).to eq(%w[b c])
|
204
206
|
expect(p_c.rhs).to eq(['a', p_a, 'd', p_a])
|
205
207
|
end
|
206
208
|
|
207
209
|
it 'should cope with the "porridge" example from sequitur.info' do
|
208
210
|
# Another example from sequitur.info website
|
209
|
-
input =
|
210
|
-
pease porridge hot,
|
211
|
-
pease porridge cold,
|
212
|
-
pease porridge in the pot,
|
213
|
-
nine days old.
|
214
|
-
|
215
|
-
some like it hot,
|
216
|
-
some like it cold,
|
217
|
-
some like it in the pot,
|
218
|
-
nine days old.
|
219
|
-
SNIPPET
|
211
|
+
input = <<~SNIPPET
|
212
|
+
pease porridge hot,
|
213
|
+
pease porridge cold,
|
214
|
+
pease porridge in the pot,
|
215
|
+
nine days old.
|
216
|
+
|
217
|
+
some like it hot,
|
218
|
+
some like it cold,
|
219
|
+
some like it in the pot,
|
220
|
+
nine days old.
|
221
|
+
SNIPPET
|
220
222
|
# Expectations (sequitur.org)
|
221
223
|
# 0 → 1 2 3 4 3 5 ↵ 6 2 7 4 7 5
|
222
224
|
# 1 → p e a s 8 r r i d g 9 pease_porridge_
|
@@ -233,7 +235,7 @@ SNIPPET
|
|
233
235
|
# 11 → o l d old
|
234
236
|
# 12 → i n in
|
235
237
|
|
236
|
-
instance =
|
238
|
+
instance = sequitur_grammar(input.chars)
|
237
239
|
expect(instance.productions.size).to eq(13)
|
238
240
|
p0 = instance.start
|
239
241
|
expect(p0.rhs.size).to eq(13)
|
@@ -241,7 +243,7 @@ SNIPPET
|
|
241
243
|
(p1, p2, p3, p4, p5, p6, p7, p8, p9) = instance.productions[1..9]
|
242
244
|
(p10, p11, p12) = instance.productions[10..12]
|
243
245
|
|
244
|
-
#
|
246
|
+
# NOTE: the productions aren't sorted the same way as
|
245
247
|
# the sequitur.info implementation.
|
246
248
|
p0_expectation = [
|
247
249
|
p2, p8, p3, p10, p3, p12, "\n",
|
@@ -249,27 +251,27 @@ SNIPPET
|
|
249
251
|
]
|
250
252
|
expect(p0.rhs).to eq(p0_expectation) # Rule 0 above
|
251
253
|
expect(p1.rhs).to eq(['e', ' ']) # Rule 9 above
|
252
|
-
expect(p2.rhs).to eq([%w
|
254
|
+
expect(p2.rhs).to eq([%w[p e a s], p4, %w[r r i d g], p1].flatten) # R1
|
253
255
|
expect(p3.rhs).to eq([p5, p2]) # Rule 3 above
|
254
256
|
expect(p4.rhs).to eq([p1, 'p', 'o']) # Rule 8 above
|
255
257
|
expect(p5.rhs).to eq([',', "\n"]) # Rule 10 above
|
256
|
-
expect(p6.rhs).to eq(%w
|
257
|
-
expect(p7.rhs).to eq(%w
|
258
|
-
expect(p8.rhs).to eq(%w
|
259
|
-
p9_expectation = [%w
|
258
|
+
expect(p6.rhs).to eq(%w[i n]) # Rule 12 above
|
259
|
+
expect(p7.rhs).to eq(%w[o l d]) # Rule 11 above
|
260
|
+
expect(p8.rhs).to eq(%w[h o t]) # Rule 2 above
|
261
|
+
p9_expectation = [%w[s o m], p1, %w[l i k], p1, 'i', 't', ' '].flatten
|
260
262
|
expect(p9.rhs).to eq(p9_expectation) # Rule 6 above
|
261
263
|
expect(p10.rhs).to eq(['c', p7]) # Rule 4 above
|
262
264
|
expect(p11.rhs).to eq([p5, p9]) # Rule 7 above
|
263
265
|
p12_expectation = [
|
264
266
|
p6, ' ', 't', 'h', p4, 't', p5, 'n', p6, p1,
|
265
|
-
%w
|
267
|
+
%w[d a y s], ' ', p7, '.', "\n"
|
266
268
|
].flatten
|
267
269
|
expect(p12.rhs).to eq(p12_expectation) # Rule 5 above
|
268
270
|
end
|
269
271
|
|
270
272
|
it 'should work with a sequence of Ruby Symbols' do
|
271
273
|
input = 'abcabdabcabd'.chars.map(&:to_sym)
|
272
|
-
instance =
|
274
|
+
instance = sequitur_grammar(input.to_enum)
|
273
275
|
|
274
276
|
# Expectations:
|
275
277
|
# start : P2 P2.
|
@@ -286,19 +288,18 @@ SNIPPET
|
|
286
288
|
|
287
289
|
context 'Generating a text representation of itself:' do
|
288
290
|
it 'should generate a text representation when empty' do
|
289
|
-
instance =
|
291
|
+
instance = sequitur_grammar(empty_enum)
|
290
292
|
expectation = "#{instance.start.object_id} : ."
|
291
293
|
|
292
294
|
expect(instance.to_string).to eq(expectation)
|
293
295
|
end
|
294
296
|
|
295
297
|
it 'should generate a text representation of a simple production' do
|
296
|
-
instance =
|
298
|
+
instance = sequitur_grammar([:a].to_enum)
|
297
299
|
expectation = "#{instance.start.object_id} : a."
|
298
300
|
expect(instance.to_string).to eq(expectation)
|
299
301
|
end
|
300
302
|
end # context
|
301
303
|
end # describe
|
302
|
-
end # module
|
303
304
|
|
304
305
|
# End of file
|