sequitur 0.1.13 → 0.1.14
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/.rubocop.yml +5 -4
- data/CHANGELOG.md +7 -2
- data/Rakefile +4 -6
- data/lib/sequitur.rb +0 -1
- data/lib/sequitur/constants.rb +1 -1
- data/lib/sequitur/digram.rb +0 -3
- data/lib/sequitur/dynamic_grammar.rb +0 -3
- data/lib/sequitur/formatter/base_formatter.rb +0 -3
- data/lib/sequitur/formatter/base_text.rb +0 -3
- data/lib/sequitur/formatter/debug.rb +0 -3
- data/lib/sequitur/grammar_visitor.rb +0 -4
- data/lib/sequitur/production.rb +0 -5
- data/lib/sequitur/production_ref.rb +0 -4
- data/lib/sequitur/sequitur_grammar.rb +0 -4
- data/lib/sequitur/symbol_sequence.rb +6 -8
- data/spec/sequitur/digram_spec.rb +0 -8
- data/spec/sequitur/dynamic_grammar_spec.rb +144 -159
- data/spec/sequitur/formatter/base_text_spec.rb +92 -95
- data/spec/sequitur/formatter/debug_spec.rb +111 -114
- data/spec/sequitur/grammar_visitor_spec.rb +80 -88
- data/spec/sequitur/production_ref_spec.rb +102 -111
- data/spec/sequitur/production_spec.rb +361 -376
- data/spec/sequitur/sequitur_grammar_spec.rb +1 -5
- data/spec/sequitur/symbol_sequence_spec.rb +115 -124
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
YTYxNDJlM2U5ZWQ1YTk3OGQzOTYyODhjMWNmMDU1ZWQwYzZjNTY0Yg==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
NmFiMDlmY2E4YjMzYjFkNTRhNzY2M2M0NTdjNTRkM2QxYzE1ZGJkOA==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
ZDYxMGQ1NmRjNWQ5M2MwODBhZjliNmJhZTQ5ZWMwMmI1NzA1NTEwNjhiNmYx
|
10
|
+
ZmYxYjg1NDMzMmE5NzJhNjY2OTQyMjUyMDhlYzU0Y2Y0NmQzYWU3ZTUxMjYw
|
11
|
+
ZDc4NzE0MTEwZmQzMTRhNDZiM2VmMGI2NDk5ZjM4YmJjNDdhMDc=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
NzEwYzcwOTI4NWUyYTNjZmE3MDkyNjcxYWM2MDJkYjkzYWI1YWE3YmRhZjg4
|
14
|
+
YzAxMTQ0NWM1ZTRmNzFhNjZiZTUyYTIzODE3ODY4ZGJhMGQzMmY1MmEzZTI0
|
15
|
+
MWYwMDlkYmMzMzNhYTRkNGQzOGU5YmI5ZWM1OWNmMTQ3NjgxYzI=
|
data/.rubocop.yml
CHANGED
@@ -3,7 +3,11 @@ AllCops:
|
|
3
3
|
- 'examples/**/*'
|
4
4
|
- 'features/**/*'
|
5
5
|
- 'gems/**/*'
|
6
|
+
- 'lab/**/*'
|
6
7
|
|
8
|
+
AbcSize:
|
9
|
+
Max: 20
|
10
|
+
|
7
11
|
# This is disabled because some demos use UTF-8
|
8
12
|
AsciiComments:
|
9
13
|
Enabled: false
|
@@ -34,10 +38,7 @@ Documentation:
|
|
34
38
|
Enabled: false
|
35
39
|
|
36
40
|
EmptyLines:
|
37
|
-
Enabled: false
|
38
|
-
|
39
|
-
EmptyLinesAroundBody:
|
40
|
-
Enabled: false
|
41
|
+
Enabled: false
|
41
42
|
|
42
43
|
Encoding:
|
43
44
|
Enabled: false
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,10 @@
|
|
1
|
-
### 0.1.
|
2
|
-
* [
|
1
|
+
### 0.1.14 / 2015-02-06
|
2
|
+
* [CHANGE] Code re-formatted to please Rubocop 0.29
|
3
|
+
* [FIX] File `.rubocop.yml`: removal of setting for obsolete EmptyLinesAroundBody cop.
|
4
|
+
|
5
|
+
|
6
|
+
### 0.1.13 / 2015-02-05
|
7
|
+
* [FIX] File `LICENSE.txt`: was missing in the distribution but was referenced in README.
|
3
8
|
* [CHANGE] File `README.md`: added badge from license (MIT).
|
4
9
|
|
5
10
|
|
data/Rakefile
CHANGED
@@ -2,12 +2,10 @@ require 'rubygems'
|
|
2
2
|
require_relative './lib/sequitur/constants'
|
3
3
|
|
4
4
|
namespace :gem do
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
end
|
10
|
-
|
5
|
+
desc 'Push the gem to rubygems.org'
|
6
|
+
task :push do
|
7
|
+
system("gem push sequitur-#{Sequitur::Version}.gem")
|
8
|
+
end
|
11
9
|
end # namespace
|
12
10
|
|
13
11
|
# Testing-specific tasks
|
data/lib/sequitur.rb
CHANGED
data/lib/sequitur/constants.rb
CHANGED
data/lib/sequitur/digram.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# File: digram.rb
|
2
2
|
|
3
3
|
module Sequitur # Module for classes implementing the Sequitur algorithm
|
4
|
-
|
5
4
|
# In linguistics, a digram is a sequence of two letters.
|
6
5
|
# In Sequitur, a digram is a sequence of two consecutive symbols that
|
7
6
|
# appear in a production rule. Each symbol in a digram
|
@@ -44,9 +43,7 @@ class Digram
|
|
44
43
|
def repeating?()
|
45
44
|
return symbols[0] == symbols[1]
|
46
45
|
end
|
47
|
-
|
48
46
|
end # class
|
49
|
-
|
50
47
|
end # module
|
51
48
|
|
52
49
|
# End of file
|
@@ -2,7 +2,6 @@ require_relative 'production'
|
|
2
2
|
require_relative 'grammar_visitor'
|
3
3
|
|
4
4
|
module Sequitur # Module for classes implementing the Sequitur algorithm
|
5
|
-
|
6
5
|
# A dynamic grammar is a context-free grammar that can be built incrementally.
|
7
6
|
# Formally, a grammar has:
|
8
7
|
# One start production
|
@@ -100,7 +99,5 @@ class DynamicGrammar
|
|
100
99
|
aProduction.append_symbol(aSymbol)
|
101
100
|
end
|
102
101
|
end # class
|
103
|
-
|
104
102
|
end # module
|
105
|
-
|
106
103
|
# End of file
|
@@ -1,8 +1,6 @@
|
|
1
1
|
module Sequitur
|
2
|
-
|
3
2
|
# Namespace dedicated to grammar formatters.
|
4
3
|
module Formatter
|
5
|
-
|
6
4
|
# Superclass for grammar formatters.
|
7
5
|
class BaseFormatter
|
8
6
|
# The IO output stream in which the formatter's result will be sent.
|
@@ -31,7 +29,6 @@ module Sequitur
|
|
31
29
|
a_visitor.start
|
32
30
|
a_visitor.unsubscribe(self)
|
33
31
|
end
|
34
|
-
|
35
32
|
end # class
|
36
33
|
end # module
|
37
34
|
end # module
|
@@ -2,7 +2,6 @@ require_relative 'base_formatter'
|
|
2
2
|
|
3
3
|
module Sequitur
|
4
4
|
module Formatter
|
5
|
-
|
6
5
|
# A formatter class that can render a dynamic grammar in plain text.
|
7
6
|
# @example
|
8
7
|
# some_grammar = ... # Points to a DynamicGrammar-like object
|
@@ -11,7 +10,6 @@ module Sequitur
|
|
11
10
|
# # Render the grammar (through a visitor)
|
12
11
|
# formatter.run(some_grammar.visitor)
|
13
12
|
class BaseText < BaseFormatter
|
14
|
-
|
15
13
|
# Constructor.
|
16
14
|
# @param anIO [IO] The output stream to which the rendered grammar
|
17
15
|
# is written.
|
@@ -87,7 +85,6 @@ module Sequitur
|
|
87
85
|
name = (prod_index == 0) ? 'start' : "P#{prod_index}"
|
88
86
|
return name
|
89
87
|
end
|
90
|
-
|
91
88
|
end # class
|
92
89
|
end # module
|
93
90
|
end # module
|
@@ -3,7 +3,6 @@ require_relative 'base_formatter'
|
|
3
3
|
|
4
4
|
module Sequitur
|
5
5
|
module Formatter
|
6
|
-
|
7
6
|
# A formatter class that can render the notification events
|
8
7
|
# from a grammar visitor
|
9
8
|
# @example
|
@@ -123,9 +122,7 @@ module Sequitur
|
|
123
122
|
def output_event(anEvent, indentationLevel)
|
124
123
|
output.puts "#{' ' * 2 * indentationLevel}#{anEvent}"
|
125
124
|
end
|
126
|
-
|
127
125
|
end # class
|
128
126
|
end # module
|
129
127
|
end # module
|
130
|
-
|
131
128
|
# End of file
|
@@ -1,5 +1,4 @@
|
|
1
1
|
module Sequitur # Module for classes implementing the Sequitur algorithm
|
2
|
-
|
3
2
|
# A visitor class dedicated in the visit of Grammar.
|
4
3
|
class GrammarVisitor
|
5
4
|
# Link to the grammar to visit
|
@@ -101,10 +100,7 @@ class GrammarVisitor
|
|
101
100
|
a_subscriber.send(msg, *args)
|
102
101
|
end
|
103
102
|
end
|
104
|
-
|
105
|
-
|
106
103
|
end # class
|
107
|
-
|
108
104
|
end # module
|
109
105
|
|
110
106
|
# End of file
|
data/lib/sequitur/production.rb
CHANGED
@@ -3,8 +3,6 @@ require_relative 'symbol_sequence'
|
|
3
3
|
require_relative 'production_ref'
|
4
4
|
|
5
5
|
module Sequitur # Module for classes implementing the Sequitur algorithm
|
6
|
-
|
7
|
-
|
8
6
|
# In a context-free grammar, a production is a rule in which
|
9
7
|
# its left-hand side (LHS) consists solely of a non-terminal symbol
|
10
8
|
# and the right-hand side (RHS) consists of a sequence of symbols.
|
@@ -171,7 +169,6 @@ class Production
|
|
171
169
|
# # Then ...
|
172
170
|
# p.positions_of(a, a) # => [0, 3]
|
173
171
|
def positions_of(symb1, symb2)
|
174
|
-
|
175
172
|
# Find the positions where the digram occur in rhs
|
176
173
|
indices = [ -2 ] # Dummy index!
|
177
174
|
(0...rhs.size).each do |i|
|
@@ -232,9 +229,7 @@ class Production
|
|
232
229
|
|
233
230
|
aVisitor.end_visit_production(self)
|
234
231
|
end
|
235
|
-
|
236
232
|
end # class
|
237
|
-
|
238
233
|
end # module
|
239
234
|
|
240
235
|
# End of file
|
@@ -1,7 +1,6 @@
|
|
1
1
|
|
2
2
|
|
3
3
|
module Sequitur # Module for classes implementing the Sequitur algorithm
|
4
|
-
|
5
4
|
# A production reference is a grammar symbol that may appear in the right-hand
|
6
5
|
# side of a production P1 and that refers to a production P2.
|
7
6
|
# Every time a production P2 appears in the left-hand side of
|
@@ -18,7 +17,6 @@ module Sequitur # Module for classes implementing the Sequitur algorithm
|
|
18
17
|
# # ... Production reference count is updated...
|
19
18
|
# puts prod.refcount # outputs 1
|
20
19
|
class ProductionRef
|
21
|
-
|
22
20
|
# Link to the production to reference.
|
23
21
|
attr_reader(:production)
|
24
22
|
|
@@ -111,9 +109,7 @@ class ProductionRef
|
|
111
109
|
def accept(aVisitor)
|
112
110
|
aVisitor.visit_prod_ref(self)
|
113
111
|
end
|
114
|
-
|
115
112
|
end # class
|
116
|
-
|
117
113
|
end # module
|
118
114
|
|
119
115
|
# End of file
|
@@ -2,12 +2,10 @@ require_relative 'dynamic_grammar'
|
|
2
2
|
|
3
3
|
|
4
4
|
module Sequitur # Module for classes implementing the Sequitur algorithm
|
5
|
-
|
6
5
|
# Specialization of the DynamicGrammar class.
|
7
6
|
# A Sequitur grammar is a context-free grammar that is entirely built
|
8
7
|
# from a sequence of input tokens through the Sequitur algorithm.
|
9
8
|
class SequiturGrammar < DynamicGrammar
|
10
|
-
|
11
9
|
# Build the grammar from an enumerator of tokens.
|
12
10
|
# @param anEnum [Enumerator] an enumerator that will iterate
|
13
11
|
# over the input tokens.
|
@@ -152,7 +150,5 @@ class SequiturGrammar < DynamicGrammar
|
|
152
150
|
return new_prod
|
153
151
|
end
|
154
152
|
end # class
|
155
|
-
|
156
153
|
end # module
|
157
|
-
|
158
154
|
# End of file
|
@@ -46,10 +46,10 @@ module Sequitur # Module for classes implementing the Sequitur algorithm
|
|
46
46
|
# @param aSymbol [Object] The symbol to append.
|
47
47
|
def <<(aSymbol)
|
48
48
|
symbols << aSymbol
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
49
|
+
return unless aSymbol.is_a?(ProductionRef)
|
50
|
+
|
51
|
+
@memo_references ||= []
|
52
|
+
@memo_references << aSymbol
|
53
53
|
end
|
54
54
|
|
55
55
|
# Retrieve the element from the sequence at given position.
|
@@ -71,8 +71,8 @@ module Sequitur # Module for classes implementing the Sequitur algorithm
|
|
71
71
|
same = symbols == other.symbols
|
72
72
|
when Array
|
73
73
|
same = symbols == other
|
74
|
-
|
75
|
-
|
74
|
+
else
|
75
|
+
same = false
|
76
76
|
end
|
77
77
|
|
78
78
|
return same
|
@@ -176,7 +176,5 @@ module Sequitur # Module for classes implementing the Sequitur algorithm
|
|
176
176
|
@memo_references = nil
|
177
177
|
@lookup_references = nil
|
178
178
|
end
|
179
|
-
|
180
179
|
end # class
|
181
|
-
|
182
180
|
end # module
|
@@ -4,13 +4,11 @@ require_relative '../spec_helper'
|
|
4
4
|
require_relative '../../lib/sequitur/digram'
|
5
5
|
|
6
6
|
module Sequitur # Re-open the module to get rid of qualified names
|
7
|
-
|
8
7
|
describe Digram do
|
9
8
|
let(:two_symbols) { [:b, :c] }
|
10
9
|
let(:production) { double('sample-production') }
|
11
10
|
|
12
11
|
context 'Standard creation & initialization:' do
|
13
|
-
|
14
12
|
it 'should be created with 3 arguments' do
|
15
13
|
instance = Digram.new(:b, :c, production)
|
16
14
|
|
@@ -30,11 +28,9 @@ describe Digram do
|
|
30
28
|
instance1 = Digram.new(:a, :b, production)
|
31
29
|
expect(instance1).not_to be_repeating
|
32
30
|
end
|
33
|
-
|
34
31
|
end # context
|
35
32
|
|
36
33
|
context 'Provided services:' do
|
37
|
-
|
38
34
|
it 'should compare itself to another digram' do
|
39
35
|
instance1 = Digram.new(:a, :b, production)
|
40
36
|
same = Digram.new(:a, :b, production)
|
@@ -45,12 +41,8 @@ describe Digram do
|
|
45
41
|
expect(instance1).not_to eq(different)
|
46
42
|
expect(same).not_to eq(different)
|
47
43
|
end
|
48
|
-
|
49
44
|
end # context
|
50
|
-
|
51
|
-
|
52
45
|
end # describe
|
53
|
-
|
54
46
|
end # module
|
55
47
|
|
56
48
|
# End of file
|
@@ -1,159 +1,144 @@
|
|
1
|
-
require_relative '../spec_helper'
|
2
|
-
|
3
|
-
# Load the class under test
|
4
|
-
require_relative '../../lib/sequitur/dynamic_grammar'
|
5
|
-
|
6
|
-
module Sequitur # Re-open the module to get rid of qualified names
|
7
|
-
|
8
|
-
|
9
|
-
#
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
let(:
|
18
|
-
let(:
|
19
|
-
let(:
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
expect(subject.
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
expect(
|
43
|
-
|
44
|
-
|
45
|
-
expect
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
expect(
|
50
|
-
|
51
|
-
|
52
|
-
expect
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
expect(subject.productions.
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
subject.
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
expect(
|
73
|
-
|
74
|
-
|
75
|
-
expect(
|
76
|
-
expect(
|
77
|
-
|
78
|
-
subject.
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
expect(subject.productions).
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
it 'should
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
expect(fake_formatter).to receive(:
|
111
|
-
|
112
|
-
|
113
|
-
expect(fake_formatter).to receive(:
|
114
|
-
|
115
|
-
expect(fake_formatter).to receive(:after_rhs)
|
116
|
-
|
117
|
-
expect(fake_formatter).to receive(:
|
118
|
-
expect(fake_formatter).to receive(:
|
119
|
-
expect(fake_formatter).to receive(:
|
120
|
-
expect(fake_formatter).to receive(:
|
121
|
-
expect(fake_formatter).to receive(:
|
122
|
-
expect(fake_formatter).to receive(:
|
123
|
-
expect(fake_formatter).to receive(:
|
124
|
-
expect(fake_formatter).to receive(:
|
125
|
-
expect(fake_formatter).to receive(:
|
126
|
-
expect(fake_formatter).to receive(:
|
127
|
-
expect(fake_formatter).to receive(:
|
128
|
-
expect(fake_formatter).to receive(:
|
129
|
-
expect(fake_formatter).to receive(:
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
end
|
146
|
-
|
147
|
-
# it 'should generate a text representation of a simple production' do
|
148
|
-
# instance = SequiturGrammar.new([:a].to_enum)
|
149
|
-
# expectation = "#{instance.start.object_id} : a."
|
150
|
-
# expect(instance.to_string).to eq(expectation)
|
151
|
-
# end
|
152
|
-
|
153
|
-
end # context
|
154
|
-
|
155
|
-
end # describe
|
156
|
-
|
157
|
-
end # module
|
158
|
-
|
159
|
-
# End of file
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
# Load the class under test
|
4
|
+
require_relative '../../lib/sequitur/dynamic_grammar'
|
5
|
+
|
6
|
+
module Sequitur # Re-open the module to get rid of qualified names
|
7
|
+
describe DynamicGrammar do
|
8
|
+
# Factory method. Build a production with the given sequence
|
9
|
+
# of symbols as its rhs.
|
10
|
+
def build_production(*symbols)
|
11
|
+
prod = Production.new
|
12
|
+
symbols.each { |symb| prod.append_symbol(symb) }
|
13
|
+
return prod
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:p_a) { build_production(:a) }
|
17
|
+
let(:p_b) { build_production(:b) }
|
18
|
+
let(:p_c) { build_production(:c) }
|
19
|
+
let(:p_bc) { build_production(p_b, p_c) }
|
20
|
+
|
21
|
+
|
22
|
+
context 'Creation & initialization:' do
|
23
|
+
it 'should be created without parameter' do
|
24
|
+
expect { DynamicGrammar.new }.not_to raise_error
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should have an empty start/start production' do
|
28
|
+
expect(subject.start).to be_empty
|
29
|
+
expect(subject.productions.size).to eq(1)
|
30
|
+
expect(subject.productions.first).to be_empty
|
31
|
+
end
|
32
|
+
end # context
|
33
|
+
|
34
|
+
|
35
|
+
context 'Adding productions to the grammar:' do
|
36
|
+
it 'should add a simple production' do
|
37
|
+
subject.add_production(p_a)
|
38
|
+
expect(subject.productions.size).to eq(2)
|
39
|
+
expect(subject.productions.last).to eq(p_a)
|
40
|
+
|
41
|
+
# Error: p_b, p_c not in grammar
|
42
|
+
expect { add_production(p_bc) }.to raise_error(StandardError)
|
43
|
+
|
44
|
+
subject.add_production(p_b)
|
45
|
+
expect(subject.productions.size).to eq(3)
|
46
|
+
expect(subject.productions.last).to eq(p_b)
|
47
|
+
|
48
|
+
# Error: p_c not in grammar
|
49
|
+
expect { add_production(p_bc) }.to raise_error(StandardError)
|
50
|
+
|
51
|
+
subject.add_production(p_c)
|
52
|
+
expect(subject.productions.size).to eq(4)
|
53
|
+
expect(subject.productions.last).to eq(p_c)
|
54
|
+
|
55
|
+
subject.add_production(p_bc)
|
56
|
+
expect(subject.productions.size).to eq(5)
|
57
|
+
expect(subject.productions.last).to eq(p_bc)
|
58
|
+
end
|
59
|
+
end # context
|
60
|
+
|
61
|
+
|
62
|
+
context 'Removing a production from the grammar:' do
|
63
|
+
it 'should remove an existing production' do
|
64
|
+
subject.add_production(p_a) # index = 1
|
65
|
+
subject.add_production(p_b) # index = 2
|
66
|
+
subject.add_production(p_c) # index = 3
|
67
|
+
subject.add_production(p_bc) # index = 4
|
68
|
+
expect(subject.productions.size).to eq(5)
|
69
|
+
|
70
|
+
expect(p_a.refcount).to eq(0)
|
71
|
+
expect(p_b.refcount).to eq(1)
|
72
|
+
expect(p_c.refcount).to eq(1)
|
73
|
+
|
74
|
+
subject.remove_production(1) # 1 => p_a
|
75
|
+
expect(subject.productions.size).to eq(4)
|
76
|
+
expect(p_b.refcount).to eq(1)
|
77
|
+
expect(p_c.refcount).to eq(1)
|
78
|
+
expect(subject.productions).not_to include(p_a)
|
79
|
+
|
80
|
+
subject.remove_production(3) # 3 => p_bc
|
81
|
+
|
82
|
+
expect(subject.productions.size).to eq(3)
|
83
|
+
expect(p_b.refcount).to eq(0)
|
84
|
+
expect(p_c.refcount).to eq(0)
|
85
|
+
expect(subject.productions).not_to include(p_bc)
|
86
|
+
end
|
87
|
+
end # context
|
88
|
+
|
89
|
+
context 'Visiting:' do
|
90
|
+
it 'should return a visitor' do
|
91
|
+
expect { subject.visitor }.not_to raise_error
|
92
|
+
expect(subject.visitor).to be_kind_of(GrammarVisitor)
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'should accept a visitor' do
|
96
|
+
subject.add_production(p_a) # index = 1
|
97
|
+
subject.add_production(p_b) # index = 2
|
98
|
+
subject.add_production(p_c) # index = 3
|
99
|
+
subject.add_production(p_bc) # index = 4
|
100
|
+
|
101
|
+
a_visitor = subject.visitor
|
102
|
+
fake_formatter = double('fake-formatter')
|
103
|
+
a_visitor.subscribe(fake_formatter)
|
104
|
+
|
105
|
+
expect(fake_formatter).to receive(:before_grammar).with(subject).ordered
|
106
|
+
expect(fake_formatter).to receive(:before_production)
|
107
|
+
.with(subject.start).ordered
|
108
|
+
expect(fake_formatter).to receive(:before_rhs)
|
109
|
+
.with(subject.start.rhs).ordered
|
110
|
+
expect(fake_formatter).to receive(:after_rhs)
|
111
|
+
.with(subject.start.rhs).ordered
|
112
|
+
expect(fake_formatter).to receive(:after_production).with(subject.start)
|
113
|
+
expect(fake_formatter).to receive(:before_production).with(p_a)
|
114
|
+
expect(fake_formatter).to receive(:before_rhs).with(p_a.rhs)
|
115
|
+
expect(fake_formatter).to receive(:after_rhs).with(p_a.rhs)
|
116
|
+
expect(fake_formatter).to receive(:after_production).with(p_a)
|
117
|
+
expect(fake_formatter).to receive(:before_production).with(p_b)
|
118
|
+
expect(fake_formatter).to receive(:before_rhs).with(p_b.rhs)
|
119
|
+
expect(fake_formatter).to receive(:after_rhs).with(p_b.rhs)
|
120
|
+
expect(fake_formatter).to receive(:after_production).with(p_b)
|
121
|
+
expect(fake_formatter).to receive(:before_production).with(p_c)
|
122
|
+
expect(fake_formatter).to receive(:before_rhs).with(p_c.rhs)
|
123
|
+
expect(fake_formatter).to receive(:after_rhs).with(p_c.rhs)
|
124
|
+
expect(fake_formatter).to receive(:after_production).with(p_c)
|
125
|
+
expect(fake_formatter).to receive(:before_production).with(p_bc)
|
126
|
+
expect(fake_formatter).to receive(:before_rhs).with(p_bc.rhs)
|
127
|
+
expect(fake_formatter).to receive(:after_rhs).with(p_bc.rhs)
|
128
|
+
expect(fake_formatter).to receive(:after_production).with(p_bc)
|
129
|
+
expect(fake_formatter).to receive(:after_grammar).with(subject)
|
130
|
+
subject.send(:accept, a_visitor)
|
131
|
+
end
|
132
|
+
end # context
|
133
|
+
|
134
|
+
|
135
|
+
context 'Generating a text representation of itself:' do
|
136
|
+
it 'should generate a text representation when empty' do
|
137
|
+
expectation = "#{subject.start.object_id} : ."
|
138
|
+
expect(subject.to_string).to eq(expectation)
|
139
|
+
end
|
140
|
+
end # context
|
141
|
+
end # describe
|
142
|
+
end # module
|
143
|
+
|
144
|
+
# End of file
|