sequitur 0.1.13 → 0.1.14
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 +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
|