rubysl-rexml 1.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.
Files changed (179) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.travis.yml +8 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE +25 -0
  6. data/README.md +29 -0
  7. data/Rakefile +1 -0
  8. data/lib/rexml/attlistdecl.rb +62 -0
  9. data/lib/rexml/attribute.rb +185 -0
  10. data/lib/rexml/cdata.rb +67 -0
  11. data/lib/rexml/child.rb +96 -0
  12. data/lib/rexml/comment.rb +80 -0
  13. data/lib/rexml/doctype.rb +271 -0
  14. data/lib/rexml/document.rb +230 -0
  15. data/lib/rexml/dtd/attlistdecl.rb +10 -0
  16. data/lib/rexml/dtd/dtd.rb +51 -0
  17. data/lib/rexml/dtd/elementdecl.rb +17 -0
  18. data/lib/rexml/dtd/entitydecl.rb +56 -0
  19. data/lib/rexml/dtd/notationdecl.rb +39 -0
  20. data/lib/rexml/element.rb +1227 -0
  21. data/lib/rexml/encoding.rb +71 -0
  22. data/lib/rexml/encodings/CP-1252.rb +103 -0
  23. data/lib/rexml/encodings/EUC-JP.rb +35 -0
  24. data/lib/rexml/encodings/ICONV.rb +22 -0
  25. data/lib/rexml/encodings/ISO-8859-1.rb +7 -0
  26. data/lib/rexml/encodings/ISO-8859-15.rb +72 -0
  27. data/lib/rexml/encodings/SHIFT-JIS.rb +37 -0
  28. data/lib/rexml/encodings/SHIFT_JIS.rb +1 -0
  29. data/lib/rexml/encodings/UNILE.rb +34 -0
  30. data/lib/rexml/encodings/US-ASCII.rb +30 -0
  31. data/lib/rexml/encodings/UTF-16.rb +35 -0
  32. data/lib/rexml/encodings/UTF-8.rb +18 -0
  33. data/lib/rexml/entity.rb +166 -0
  34. data/lib/rexml/formatters/default.rb +109 -0
  35. data/lib/rexml/formatters/pretty.rb +138 -0
  36. data/lib/rexml/formatters/transitive.rb +56 -0
  37. data/lib/rexml/functions.rb +382 -0
  38. data/lib/rexml/instruction.rb +70 -0
  39. data/lib/rexml/light/node.rb +196 -0
  40. data/lib/rexml/namespace.rb +47 -0
  41. data/lib/rexml/node.rb +75 -0
  42. data/lib/rexml/output.rb +24 -0
  43. data/lib/rexml/parent.rb +166 -0
  44. data/lib/rexml/parseexception.rb +51 -0
  45. data/lib/rexml/parsers/baseparser.rb +503 -0
  46. data/lib/rexml/parsers/lightparser.rb +60 -0
  47. data/lib/rexml/parsers/pullparser.rb +196 -0
  48. data/lib/rexml/parsers/sax2parser.rb +238 -0
  49. data/lib/rexml/parsers/streamparser.rb +46 -0
  50. data/lib/rexml/parsers/treeparser.rb +97 -0
  51. data/lib/rexml/parsers/ultralightparser.rb +56 -0
  52. data/lib/rexml/parsers/xpathparser.rb +698 -0
  53. data/lib/rexml/quickpath.rb +266 -0
  54. data/lib/rexml/rexml.rb +32 -0
  55. data/lib/rexml/sax2listener.rb +97 -0
  56. data/lib/rexml/source.rb +251 -0
  57. data/lib/rexml/streamlistener.rb +92 -0
  58. data/lib/rexml/syncenumerator.rb +33 -0
  59. data/lib/rexml/text.rb +344 -0
  60. data/lib/rexml/undefinednamespaceexception.rb +8 -0
  61. data/lib/rexml/validation/relaxng.rb +559 -0
  62. data/lib/rexml/validation/validation.rb +155 -0
  63. data/lib/rexml/validation/validationexception.rb +9 -0
  64. data/lib/rexml/xmldecl.rb +119 -0
  65. data/lib/rexml/xmltokens.rb +18 -0
  66. data/lib/rexml/xpath.rb +66 -0
  67. data/lib/rexml/xpath_parser.rb +792 -0
  68. data/lib/rubysl/rexml.rb +1 -0
  69. data/lib/rubysl/rexml/version.rb +5 -0
  70. data/rubysl-rexml.gemspec +23 -0
  71. data/spec/attribute/clone_spec.rb +10 -0
  72. data/spec/attribute/element_spec.rb +22 -0
  73. data/spec/attribute/equal_value_spec.rb +17 -0
  74. data/spec/attribute/hash_spec.rb +12 -0
  75. data/spec/attribute/initialize_spec.rb +28 -0
  76. data/spec/attribute/inspect_spec.rb +19 -0
  77. data/spec/attribute/namespace_spec.rb +23 -0
  78. data/spec/attribute/node_type_spec.rb +9 -0
  79. data/spec/attribute/prefix_spec.rb +17 -0
  80. data/spec/attribute/remove_spec.rb +19 -0
  81. data/spec/attribute/to_s_spec.rb +13 -0
  82. data/spec/attribute/to_string_spec.rb +14 -0
  83. data/spec/attribute/value_spec.rb +14 -0
  84. data/spec/attribute/write_spec.rb +22 -0
  85. data/spec/attribute/xpath_spec.rb +19 -0
  86. data/spec/attributes/add_spec.rb +6 -0
  87. data/spec/attributes/append_spec.rb +6 -0
  88. data/spec/attributes/delete_all_spec.rb +30 -0
  89. data/spec/attributes/delete_spec.rb +26 -0
  90. data/spec/attributes/each_attribute_spec.rb +24 -0
  91. data/spec/attributes/each_spec.rb +24 -0
  92. data/spec/attributes/element_reference_spec.rb +18 -0
  93. data/spec/attributes/element_set_spec.rb +25 -0
  94. data/spec/attributes/get_attribute_ns_spec.rb +13 -0
  95. data/spec/attributes/get_attribute_spec.rb +28 -0
  96. data/spec/attributes/initialize_spec.rb +18 -0
  97. data/spec/attributes/length_spec.rb +6 -0
  98. data/spec/attributes/namespaces_spec.rb +5 -0
  99. data/spec/attributes/prefixes_spec.rb +23 -0
  100. data/spec/attributes/shared/add.rb +17 -0
  101. data/spec/attributes/shared/length.rb +12 -0
  102. data/spec/attributes/size_spec.rb +6 -0
  103. data/spec/attributes/to_a_spec.rb +20 -0
  104. data/spec/cdata/clone_spec.rb +9 -0
  105. data/spec/cdata/initialize_spec.rb +24 -0
  106. data/spec/cdata/shared/to_s.rb +11 -0
  107. data/spec/cdata/to_s_spec.rb +6 -0
  108. data/spec/cdata/value_spec.rb +6 -0
  109. data/spec/document/add_element_spec.rb +30 -0
  110. data/spec/document/add_spec.rb +60 -0
  111. data/spec/document/clone_spec.rb +19 -0
  112. data/spec/document/doctype_spec.rb +14 -0
  113. data/spec/document/encoding_spec.rb +21 -0
  114. data/spec/document/expanded_name_spec.rb +15 -0
  115. data/spec/document/new_spec.rb +37 -0
  116. data/spec/document/node_type_spec.rb +7 -0
  117. data/spec/document/root_spec.rb +11 -0
  118. data/spec/document/stand_alone_spec.rb +18 -0
  119. data/spec/document/version_spec.rb +13 -0
  120. data/spec/document/write_spec.rb +38 -0
  121. data/spec/document/xml_decl_spec.rb +14 -0
  122. data/spec/element/add_attribute_spec.rb +40 -0
  123. data/spec/element/add_attributes_spec.rb +21 -0
  124. data/spec/element/add_element_spec.rb +38 -0
  125. data/spec/element/add_namespace_spec.rb +23 -0
  126. data/spec/element/add_text_spec.rb +23 -0
  127. data/spec/element/attribute_spec.rb +16 -0
  128. data/spec/element/attributes_spec.rb +18 -0
  129. data/spec/element/cdatas_spec.rb +23 -0
  130. data/spec/element/clone_spec.rb +28 -0
  131. data/spec/element/comments_spec.rb +20 -0
  132. data/spec/element/delete_attribute_spec.rb +38 -0
  133. data/spec/element/delete_element_spec.rb +50 -0
  134. data/spec/element/delete_namespace_spec.rb +24 -0
  135. data/spec/element/document_spec.rb +17 -0
  136. data/spec/element/each_element_with_attribute_spec.rb +34 -0
  137. data/spec/element/each_element_with_text_spec.rb +30 -0
  138. data/spec/element/get_text_spec.rb +17 -0
  139. data/spec/element/has_attributes_spec.rb +16 -0
  140. data/spec/element/has_elements_spec.rb +17 -0
  141. data/spec/element/has_text_spec.rb +15 -0
  142. data/spec/element/inspect_spec.rb +26 -0
  143. data/spec/element/instructions_spec.rb +20 -0
  144. data/spec/element/namespace_spec.rb +26 -0
  145. data/spec/element/namespaces_spec.rb +31 -0
  146. data/spec/element/new_spec.rb +34 -0
  147. data/spec/element/next_element_spec.rb +18 -0
  148. data/spec/element/node_type_spec.rb +7 -0
  149. data/spec/element/prefixes_spec.rb +22 -0
  150. data/spec/element/previous_element_spec.rb +19 -0
  151. data/spec/element/raw_spec.rb +23 -0
  152. data/spec/element/root_spec.rb +27 -0
  153. data/spec/element/text_spec.rb +45 -0
  154. data/spec/element/texts_spec.rb +15 -0
  155. data/spec/element/whitespace_spec.rb +22 -0
  156. data/spec/node/each_recursive_spec.rb +20 -0
  157. data/spec/node/find_first_recursive_spec.rb +24 -0
  158. data/spec/node/index_in_parent_spec.rb +14 -0
  159. data/spec/node/next_sibling_node_spec.rb +20 -0
  160. data/spec/node/parent_spec.rb +20 -0
  161. data/spec/node/previous_sibling_node_spec.rb +20 -0
  162. data/spec/shared/each_element.rb +35 -0
  163. data/spec/shared/elements_to_a.rb +35 -0
  164. data/spec/text/append_spec.rb +9 -0
  165. data/spec/text/clone_spec.rb +9 -0
  166. data/spec/text/comparison_spec.rb +24 -0
  167. data/spec/text/empty_spec.rb +11 -0
  168. data/spec/text/indent_text_spec.rb +23 -0
  169. data/spec/text/inspect_spec.rb +7 -0
  170. data/spec/text/new_spec.rb +48 -0
  171. data/spec/text/node_type_spec.rb +7 -0
  172. data/spec/text/normalize_spec.rb +7 -0
  173. data/spec/text/read_with_substitution_spec.rb +12 -0
  174. data/spec/text/to_s_spec.rb +17 -0
  175. data/spec/text/unnormalize_spec.rb +7 -0
  176. data/spec/text/value_spec.rb +36 -0
  177. data/spec/text/wrap_spec.rb +20 -0
  178. data/spec/text/write_with_substitution_spec.rb +32 -0
  179. metadata +385 -0
@@ -0,0 +1,8 @@
1
+ require 'rexml/parseexception'
2
+ module REXML
3
+ class UndefinedNamespaceException < ParseException
4
+ def initialize( prefix, source, parser )
5
+ super( "Undefined prefix #{prefix} found" )
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,559 @@
1
+ require "rexml/validation/validation"
2
+ require "rexml/parsers/baseparser"
3
+
4
+ module REXML
5
+ module Validation
6
+ # Implemented:
7
+ # * empty
8
+ # * element
9
+ # * attribute
10
+ # * text
11
+ # * optional
12
+ # * choice
13
+ # * oneOrMore
14
+ # * zeroOrMore
15
+ # * group
16
+ # * value
17
+ # * interleave
18
+ # * mixed
19
+ # * ref
20
+ # * grammar
21
+ # * start
22
+ # * define
23
+ #
24
+ # Not implemented:
25
+ # * data
26
+ # * param
27
+ # * include
28
+ # * externalRef
29
+ # * notAllowed
30
+ # * anyName
31
+ # * nsName
32
+ # * except
33
+ # * name
34
+ class RelaxNG
35
+ include Validator
36
+
37
+ INFINITY = 1.0 / 0.0
38
+ EMPTY = Event.new( nil )
39
+ TEXT = [:start_element, "text"]
40
+ attr_accessor :current
41
+ attr_accessor :count
42
+ attr_reader :references
43
+
44
+ # FIXME: Namespaces
45
+ def initialize source
46
+ parser = REXML::Parsers::BaseParser.new( source )
47
+
48
+ @count = 0
49
+ @references = {}
50
+ @root = @current = Sequence.new(self)
51
+ @root.previous = true
52
+ states = [ @current ]
53
+ begin
54
+ event = parser.pull
55
+ case event[0]
56
+ when :start_element
57
+ case event[1]
58
+ when "empty"
59
+ when "element", "attribute", "text", "value"
60
+ states[-1] << event
61
+ when "optional"
62
+ states << Optional.new( self )
63
+ states[-2] << states[-1]
64
+ when "choice"
65
+ states << Choice.new( self )
66
+ states[-2] << states[-1]
67
+ when "oneOrMore"
68
+ states << OneOrMore.new( self )
69
+ states[-2] << states[-1]
70
+ when "zeroOrMore"
71
+ states << ZeroOrMore.new( self )
72
+ states[-2] << states[-1]
73
+ when "group"
74
+ states << Sequence.new( self )
75
+ states[-2] << states[-1]
76
+ when "interleave"
77
+ states << Interleave.new( self )
78
+ states[-2] << states[-1]
79
+ when "mixed"
80
+ states << Interleave.new( self )
81
+ states[-2] << states[-1]
82
+ states[-1] << TEXT
83
+ when "define"
84
+ states << [ event[2]["name"] ]
85
+ when "ref"
86
+ states[-1] << Ref.new( event[2]["name"] )
87
+ when "anyName"
88
+ states << AnyName.new( self )
89
+ states[-2] << states[-1]
90
+ when "nsName"
91
+ when "except"
92
+ when "name"
93
+ when "data"
94
+ when "param"
95
+ when "include"
96
+ when "grammar"
97
+ when "start"
98
+ when "externalRef"
99
+ when "notAllowed"
100
+ end
101
+ when :end_element
102
+ case event[1]
103
+ when "element", "attribute"
104
+ states[-1] << event
105
+ when "zeroOrMore", "oneOrMore", "choice", "optional",
106
+ "interleave", "group", "mixed"
107
+ states.pop
108
+ when "define"
109
+ ref = states.pop
110
+ @references[ ref.shift ] = ref
111
+ #when "empty"
112
+ end
113
+ when :end_document
114
+ states[-1] << event
115
+ when :text
116
+ states[-1] << event
117
+ end
118
+ end while event[0] != :end_document
119
+ end
120
+
121
+ def receive event
122
+ validate( event )
123
+ end
124
+ end
125
+
126
+ class State
127
+ def initialize( context )
128
+ @previous = []
129
+ @events = []
130
+ @current = 0
131
+ @count = context.count += 1
132
+ @references = context.references
133
+ @value = false
134
+ end
135
+
136
+ def reset
137
+ return if @current == 0
138
+ @current = 0
139
+ @events.each {|s| s.reset if s.kind_of? State }
140
+ end
141
+
142
+ def previous=( previous )
143
+ @previous << previous
144
+ end
145
+
146
+ def next( event )
147
+ #print "In next with #{event.inspect}. "
148
+ #puts "Next (#@current) is #{@events[@current]}"
149
+ #p @previous
150
+ return @previous.pop.next( event ) if @events[@current].nil?
151
+ expand_ref_in( @events, @current ) if @events[@current].class == Ref
152
+ if ( @events[@current].kind_of? State )
153
+ @current += 1
154
+ @events[@current-1].previous = self
155
+ return @events[@current-1].next( event )
156
+ end
157
+ #puts "Current isn't a state"
158
+ if ( @events[@current].matches?(event) )
159
+ @current += 1
160
+ if @events[@current].nil?
161
+ #puts "#{inspect[0,5]} 1RETURNING #{@previous.inspect[0,5]}"
162
+ return @previous.pop
163
+ elsif @events[@current].kind_of? State
164
+ @current += 1
165
+ #puts "#{inspect[0,5]} 2RETURNING (#{@current-1}) #{@events[@current-1].inspect[0,5]}; on return, next is #{@events[@current]}"
166
+ @events[@current-1].previous = self
167
+ return @events[@current-1]
168
+ else
169
+ #puts "#{inspect[0,5]} RETURNING self w/ next(#@current) = #{@events[@current]}"
170
+ return self
171
+ end
172
+ else
173
+ return nil
174
+ end
175
+ end
176
+
177
+ def to_s
178
+ # Abbreviated:
179
+ self.class.name =~ /(?:::)(\w)\w+$/
180
+ # Full:
181
+ #self.class.name =~ /(?:::)(\w+)$/
182
+ "#$1.#@count"
183
+ end
184
+
185
+ def inspect
186
+ "< #{to_s} #{@events.collect{|e|
187
+ pre = e == @events[@current] ? '#' : ''
188
+ pre + e.inspect unless self == e
189
+ }.join(', ')} >"
190
+ end
191
+
192
+ def expected
193
+ return [@events[@current]]
194
+ end
195
+
196
+ def <<( event )
197
+ add_event_to_arry( @events, event )
198
+ end
199
+
200
+
201
+ protected
202
+ def expand_ref_in( arry, ind )
203
+ new_events = []
204
+ @references[ arry[ind].to_s ].each{ |evt|
205
+ add_event_to_arry(new_events,evt)
206
+ }
207
+ arry[ind,1] = new_events
208
+ end
209
+
210
+ def add_event_to_arry( arry, evt )
211
+ evt = generate_event( evt )
212
+ if evt.kind_of? String
213
+ arry[-1].event_arg = evt if arry[-1].kind_of? Event and @value
214
+ @value = false
215
+ else
216
+ arry << evt
217
+ end
218
+ end
219
+
220
+ def generate_event( event )
221
+ return event if event.kind_of? State or event.class == Ref
222
+ evt = nil
223
+ arg = nil
224
+ case event[0]
225
+ when :start_element
226
+ case event[1]
227
+ when "element"
228
+ evt = :start_element
229
+ arg = event[2]["name"]
230
+ when "attribute"
231
+ evt = :start_attribute
232
+ arg = event[2]["name"]
233
+ when "text"
234
+ evt = :text
235
+ when "value"
236
+ evt = :text
237
+ @value = true
238
+ end
239
+ when :text
240
+ return event[1]
241
+ when :end_document
242
+ return Event.new( event[0] )
243
+ else # then :end_element
244
+ case event[1]
245
+ when "element"
246
+ evt = :end_element
247
+ when "attribute"
248
+ evt = :end_attribute
249
+ end
250
+ end
251
+ return Event.new( evt, arg )
252
+ end
253
+ end
254
+
255
+
256
+ class Sequence < State
257
+ def matches?(event)
258
+ @events[@current].matches?( event )
259
+ end
260
+ end
261
+
262
+
263
+ class Optional < State
264
+ def next( event )
265
+ if @current == 0
266
+ rv = super
267
+ return rv if rv
268
+ @prior = @previous.pop
269
+ return @prior.next( event )
270
+ end
271
+ super
272
+ end
273
+
274
+ def matches?(event)
275
+ @events[@current].matches?(event) ||
276
+ (@current == 0 and @previous[-1].matches?(event))
277
+ end
278
+
279
+ def expected
280
+ return [ @prior.expected, @events[0] ].flatten if @current == 0
281
+ return [@events[@current]]
282
+ end
283
+ end
284
+
285
+
286
+ class ZeroOrMore < Optional
287
+ def next( event )
288
+ expand_ref_in( @events, @current ) if @events[@current].class == Ref
289
+ if ( @events[@current].matches?(event) )
290
+ @current += 1
291
+ if @events[@current].nil?
292
+ @current = 0
293
+ return self
294
+ elsif @events[@current].kind_of? State
295
+ @current += 1
296
+ @events[@current-1].previous = self
297
+ return @events[@current-1]
298
+ else
299
+ return self
300
+ end
301
+ else
302
+ @prior = @previous.pop
303
+ return @prior.next( event ) if @current == 0
304
+ return nil
305
+ end
306
+ end
307
+
308
+ def expected
309
+ return [ @prior.expected, @events[0] ].flatten if @current == 0
310
+ return [@events[@current]]
311
+ end
312
+ end
313
+
314
+
315
+ class OneOrMore < State
316
+ def initialize context
317
+ super
318
+ @ord = 0
319
+ end
320
+
321
+ def reset
322
+ super
323
+ @ord = 0
324
+ end
325
+
326
+ def next( event )
327
+ expand_ref_in( @events, @current ) if @events[@current].class == Ref
328
+ if ( @events[@current].matches?(event) )
329
+ @current += 1
330
+ @ord += 1
331
+ if @events[@current].nil?
332
+ @current = 0
333
+ return self
334
+ elsif @events[@current].kind_of? State
335
+ @current += 1
336
+ @events[@current-1].previous = self
337
+ return @events[@current-1]
338
+ else
339
+ return self
340
+ end
341
+ else
342
+ return @previous.pop.next( event ) if @current == 0 and @ord > 0
343
+ return nil
344
+ end
345
+ end
346
+
347
+ def matches?( event )
348
+ @events[@current].matches?(event) ||
349
+ (@current == 0 and @ord > 0 and @previous[-1].matches?(event))
350
+ end
351
+
352
+ def expected
353
+ if @current == 0 and @ord > 0
354
+ return [@previous[-1].expected, @events[0]].flatten
355
+ else
356
+ return [@events[@current]]
357
+ end
358
+ end
359
+ end
360
+
361
+
362
+ class Choice < State
363
+ def initialize context
364
+ super
365
+ @choices = []
366
+ end
367
+
368
+ def reset
369
+ super
370
+ @events = []
371
+ @choices.each { |c| c.each { |s| s.reset if s.kind_of? State } }
372
+ end
373
+
374
+ def <<( event )
375
+ add_event_to_arry( @choices, event )
376
+ end
377
+
378
+ def next( event )
379
+ # Make the choice if we haven't
380
+ if @events.size == 0
381
+ c = 0 ; max = @choices.size
382
+ while c < max
383
+ if @choices[c][0].class == Ref
384
+ expand_ref_in( @choices[c], 0 )
385
+ @choices += @choices[c]
386
+ @choices.delete( @choices[c] )
387
+ max -= 1
388
+ else
389
+ c += 1
390
+ end
391
+ end
392
+ @events = @choices.find { |evt| evt[0].matches? event }
393
+ # Remove the references
394
+ # Find the events
395
+ end
396
+ #puts "In next with #{event.inspect}."
397
+ #puts "events is #{@events.inspect}"
398
+ unless @events
399
+ @events = []
400
+ return nil
401
+ end
402
+ #puts "current = #@current"
403
+ super
404
+ end
405
+
406
+ def matches?( event )
407
+ return @events[@current].matches?( event ) if @events.size > 0
408
+ !@choices.find{|evt| evt[0].matches?(event)}.nil?
409
+ end
410
+
411
+ def expected
412
+ #puts "IN CHOICE EXPECTED"
413
+ #puts "EVENTS = #{@events.inspect}"
414
+ return [@events[@current]] if @events.size > 0
415
+ return @choices.collect do |x|
416
+ if x[0].kind_of? State
417
+ x[0].expected
418
+ else
419
+ x[0]
420
+ end
421
+ end.flatten
422
+ end
423
+
424
+ def inspect
425
+ "< #{to_s} #{@choices.collect{|e| e.collect{|f|f.to_s}.join(', ')}.join(' or ')} >"
426
+ end
427
+
428
+ protected
429
+ def add_event_to_arry( arry, evt )
430
+ if evt.kind_of? State or evt.class == Ref
431
+ arry << [evt]
432
+ elsif evt[0] == :text
433
+ if arry[-1] and
434
+ arry[-1][-1].kind_of?( Event ) and
435
+ arry[-1][-1].event_type == :text and @value
436
+
437
+ arry[-1][-1].event_arg = evt[1]
438
+ @value = false
439
+ end
440
+ else
441
+ arry << [] if evt[0] == :start_element
442
+ arry[-1] << generate_event( evt )
443
+ end
444
+ end
445
+ end
446
+
447
+
448
+ class Interleave < Choice
449
+ def initialize context
450
+ super
451
+ @choice = 0
452
+ end
453
+
454
+ def reset
455
+ @choice = 0
456
+ end
457
+
458
+ def next_current( event )
459
+ # Expand references
460
+ c = 0 ; max = @choices.size
461
+ while c < max
462
+ if @choices[c][0].class == Ref
463
+ expand_ref_in( @choices[c], 0 )
464
+ @choices += @choices[c]
465
+ @choices.delete( @choices[c] )
466
+ max -= 1
467
+ else
468
+ c += 1
469
+ end
470
+ end
471
+ @events = @choices[@choice..-1].find { |evt| evt[0].matches? event }
472
+ @current = 0
473
+ if @events
474
+ # reorder the choices
475
+ old = @choices[@choice]
476
+ idx = @choices.index( @events )
477
+ @choices[@choice] = @events
478
+ @choices[idx] = old
479
+ @choice += 1
480
+ end
481
+
482
+ #puts "In next with #{event.inspect}."
483
+ #puts "events is #{@events.inspect}"
484
+ @events = [] unless @events
485
+ end
486
+
487
+
488
+ def next( event )
489
+ # Find the next series
490
+ next_current(event) unless @events[@current]
491
+ return nil unless @events[@current]
492
+
493
+ expand_ref_in( @events, @current ) if @events[@current].class == Ref
494
+ #puts "In next with #{event.inspect}."
495
+ #puts "Next (#@current) is #{@events[@current]}"
496
+ if ( @events[@current].kind_of? State )
497
+ @current += 1
498
+ @events[@current-1].previous = self
499
+ return @events[@current-1].next( event )
500
+ end
501
+ #puts "Current isn't a state"
502
+ return @previous.pop.next( event ) if @events[@current].nil?
503
+ if ( @events[@current].matches?(event) )
504
+ @current += 1
505
+ if @events[@current].nil?
506
+ #puts "#{inspect[0,5]} 1RETURNING self" unless @choices[@choice].nil?
507
+ return self unless @choices[@choice].nil?
508
+ #puts "#{inspect[0,5]} 1RETURNING #{@previous[-1].inspect[0,5]}"
509
+ return @previous.pop
510
+ elsif @events[@current].kind_of? State
511
+ @current += 1
512
+ #puts "#{inspect[0,5]} 2RETURNING (#{@current-1}) #{@events[@current-1].inspect[0,5]}; on return, next is #{@events[@current]}"
513
+ @events[@current-1].previous = self
514
+ return @events[@current-1]
515
+ else
516
+ #puts "#{inspect[0,5]} RETURNING self w/ next(#@current) = #{@events[@current]}"
517
+ return self
518
+ end
519
+ else
520
+ return nil
521
+ end
522
+ end
523
+
524
+ def matches?( event )
525
+ return @events[@current].matches?( event ) if @events[@current]
526
+ !@choices[@choice..-1].find{|evt| evt[0].matches?(event)}.nil?
527
+ end
528
+
529
+ def expected
530
+ #puts "IN CHOICE EXPECTED"
531
+ #puts "EVENTS = #{@events.inspect}"
532
+ return [@events[@current]] if @events[@current]
533
+ return @choices[@choice..-1].collect do |x|
534
+ if x[0].kind_of? State
535
+ x[0].expected
536
+ else
537
+ x[0]
538
+ end
539
+ end.flatten
540
+ end
541
+
542
+ def inspect
543
+ "< #{to_s} #{@choices.collect{|e| e.collect{|f|f.to_s}.join(', ')}.join(' and ')} >"
544
+ end
545
+ end
546
+
547
+ class Ref
548
+ def initialize value
549
+ @value = value
550
+ end
551
+ def to_s
552
+ @value
553
+ end
554
+ def inspect
555
+ "{#{to_s}}"
556
+ end
557
+ end
558
+ end
559
+ end