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 CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- NTk1NDVlNDJjZDIzZTY5OTE4ODI3MWM0MDc0M2EwMjIyNzRmZTk5Ng==
4
+ YTYxNDJlM2U5ZWQ1YTk3OGQzOTYyODhjMWNmMDU1ZWQwYzZjNTY0Yg==
5
5
  data.tar.gz: !binary |-
6
- MWE5OTE1MmE2NjQ0ZTk1ZmUyYzIwZTllMjFiMmE4OGU1ZGJiODZiMQ==
6
+ NmFiMDlmY2E4YjMzYjFkNTRhNzY2M2M0NTdjNTRkM2QxYzE1ZGJkOA==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- YWU0MzRlZGZjZWIyNDUzMjNhZDU3ZWFmZDIxZmExMTc0NWI1YTFjNDhkYmQ4
10
- NGMzYzc1ZWQwMGM4ZGUzMjVlN2JhNDhjMTU2YWUzYjU3OTQ4NWY2ZTFmZGE1
11
- NGQyZGM4ZTdkOTcyNjQ1MmRkNTgyM2NjYjcxYmU0NWI4NWE1ODc=
9
+ ZDYxMGQ1NmRjNWQ5M2MwODBhZjliNmJhZTQ5ZWMwMmI1NzA1NTEwNjhiNmYx
10
+ ZmYxYjg1NDMzMmE5NzJhNjY2OTQyMjUyMDhlYzU0Y2Y0NmQzYWU3ZTUxMjYw
11
+ ZDc4NzE0MTEwZmQzMTRhNDZiM2VmMGI2NDk5ZjM4YmJjNDdhMDc=
12
12
  data.tar.gz: !binary |-
13
- OTA0NjIxZWU3OGU0MjY2MWVlYWQ4NDVmYTc0NDA0ZDQyZTQ1MTQzNmZhMjRj
14
- ZDMwMmFiMzlkZGE5MmRkN2FmMGVjMWJhNWEwZmM4YjJjNWFkMDQ2YjRmMWQ3
15
- MDU3MTY3NDIwZWZiZGQ1Y2UyNTU2ODZmZWJhOWQxZDE1MDY4MzM=
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.13 / 2014-10-07
2
- * [FIX] File `LICENSE.txt`: was missing in the distribuation but was referenced in README.
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
- desc 'Push the gem to rubygems.org'
7
- task :push do
8
- system("gem push sequitur-#{Sequitur::Version}.gem")
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
@@ -9,7 +9,6 @@ require_relative './sequitur/formatter/base_text'
9
9
 
10
10
 
11
11
  module Sequitur
12
-
13
12
  # Build a Sequitur-generated grammar based on the sequence of input tokens.
14
13
  #
15
14
  # @param tokens [StringOrEnumerator] The input sequence of input tokens.
@@ -3,7 +3,7 @@
3
3
 
4
4
  module Sequitur # Module used as a namespace
5
5
  # The version number of the gem.
6
- Version = '0.1.13'
6
+ Version = '0.1.14'
7
7
 
8
8
  # Brief description of the gem.
9
9
  Description = 'Ruby implementation of the Sequitur algorithm'
@@ -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
@@ -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
- if aSymbol.is_a?(ProductionRef)
50
- @memo_references ||= []
51
- @memo_references << aSymbol
52
- end
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
- else
75
- same = false
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
- describe DynamicGrammar do
9
- # Factory method. Build a production with the given sequence
10
- # of symbols as its rhs.
11
- def build_production(*symbols)
12
- prod = Production.new
13
- symbols.each { |symb| prod.append_symbol(symb) }
14
- return prod
15
- end
16
-
17
- let(:p_a) { build_production(:a) }
18
- let(:p_b) { build_production(:b) }
19
- let(:p_c) { build_production(:c) }
20
- let(:p_bc) { build_production(p_b, p_c) }
21
-
22
-
23
- context 'Creation & initialization:' do
24
-
25
- it 'should be created without parameter' do
26
- expect { DynamicGrammar.new }.not_to raise_error
27
- end
28
-
29
- it 'should have an empty start/start production' do
30
- expect(subject.start).to be_empty
31
- expect(subject.productions.size).to eq(1)
32
- expect(subject.productions.first).to be_empty
33
- end
34
-
35
- end # context
36
-
37
-
38
- context 'Adding productions to the grammar:' do
39
- it 'should add a simple production' do
40
- subject.add_production(p_a)
41
- expect(subject.productions.size).to eq(2)
42
- expect(subject.productions.last).to eq(p_a)
43
-
44
- # Error: p_b, p_c not in grammar
45
- expect { add_production(p_bc) }.to raise_error(StandardError)
46
-
47
- subject.add_production(p_b)
48
- expect(subject.productions.size).to eq(3)
49
- expect(subject.productions.last).to eq(p_b)
50
-
51
- # Error: p_c not in grammar
52
- expect { add_production(p_bc) }.to raise_error(StandardError)
53
-
54
- subject.add_production(p_c)
55
- expect(subject.productions.size).to eq(4)
56
- expect(subject.productions.last).to eq(p_c)
57
-
58
- subject.add_production(p_bc)
59
- expect(subject.productions.size).to eq(5)
60
- expect(subject.productions.last).to eq(p_bc)
61
- end
62
-
63
- end # context
64
-
65
-
66
- context 'Removing a production from the grammar:' do
67
- it 'should remove an existing production' do
68
- subject.add_production(p_a) # index = 1
69
- subject.add_production(p_b) # index = 2
70
- subject.add_production(p_c) # index = 3
71
- subject.add_production(p_bc) # index = 4
72
- expect(subject.productions.size).to eq(5)
73
-
74
- expect(p_a.refcount).to eq(0)
75
- expect(p_b.refcount).to eq(1)
76
- expect(p_c.refcount).to eq(1)
77
-
78
- subject.remove_production(1) # 1 => p_a
79
- expect(subject.productions.size).to eq(4)
80
- expect(p_b.refcount).to eq(1)
81
- expect(p_c.refcount).to eq(1)
82
- expect(subject.productions).not_to include(p_a)
83
-
84
- subject.remove_production(3) # 3 => p_bc
85
-
86
- expect(subject.productions.size).to eq(3)
87
- expect(p_b.refcount).to eq(0)
88
- expect(p_c.refcount).to eq(0)
89
- expect(subject.productions).not_to include(p_bc)
90
- end
91
-
92
- end # context
93
-
94
- context 'Visiting:' do
95
- it 'should return a visitor' do
96
- expect { subject.visitor }.not_to raise_error
97
- expect(subject.visitor).to be_kind_of(GrammarVisitor)
98
- end
99
-
100
- it 'should accept a visitor' do
101
- subject.add_production(p_a) # index = 1
102
- subject.add_production(p_b) # index = 2
103
- subject.add_production(p_c) # index = 3
104
- subject.add_production(p_bc) # index = 4
105
-
106
- a_visitor = subject.visitor
107
- fake_formatter = double('fake-formatter')
108
- a_visitor.subscribe(fake_formatter)
109
-
110
- expect(fake_formatter).to receive(:before_grammar).with(subject).ordered
111
- expect(fake_formatter).to receive(:before_production)
112
- .with(subject.start).ordered
113
- expect(fake_formatter).to receive(:before_rhs)
114
- .with(subject.start.rhs).ordered
115
- expect(fake_formatter).to receive(:after_rhs)
116
- .with(subject.start.rhs).ordered
117
- expect(fake_formatter).to receive(:after_production).with(subject.start)
118
- expect(fake_formatter).to receive(:before_production).with(p_a)
119
- expect(fake_formatter).to receive(:before_rhs).with(p_a.rhs)
120
- expect(fake_formatter).to receive(:after_rhs).with(p_a.rhs)
121
- expect(fake_formatter).to receive(:after_production).with(p_a)
122
- expect(fake_formatter).to receive(:before_production).with(p_b)
123
- expect(fake_formatter).to receive(:before_rhs).with(p_b.rhs)
124
- expect(fake_formatter).to receive(:after_rhs).with(p_b.rhs)
125
- expect(fake_formatter).to receive(:after_production).with(p_b)
126
- expect(fake_formatter).to receive(:before_production).with(p_c)
127
- expect(fake_formatter).to receive(:before_rhs).with(p_c.rhs)
128
- expect(fake_formatter).to receive(:after_rhs).with(p_c.rhs)
129
- expect(fake_formatter).to receive(:after_production).with(p_c)
130
- expect(fake_formatter).to receive(:before_production).with(p_bc)
131
- expect(fake_formatter).to receive(:before_rhs).with(p_bc.rhs)
132
- expect(fake_formatter).to receive(:after_rhs).with(p_bc.rhs)
133
- expect(fake_formatter).to receive(:after_production).with(p_bc)
134
- expect(fake_formatter).to receive(:after_grammar).with(subject)
135
- subject.send(:accept, a_visitor)
136
- end
137
- end # context
138
-
139
-
140
- context 'Generating a text representation of itself:' do
141
-
142
- it 'should generate a text representation when empty' do
143
- expectation = "#{subject.start.object_id} : ."
144
- expect(subject.to_string).to eq(expectation)
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