rgen 0.5.4 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (125) hide show
  1. data/CHANGELOG +28 -0
  2. data/Rakefile +3 -4
  3. data/lib/ea_support/uml13_ea_metamodel.rb +3 -3
  4. data/lib/ea_support/uml13_ea_to_uml13.rb +33 -2
  5. data/lib/ea_support/uml13_to_uml13_ea.rb +7 -0
  6. data/lib/mmgen/mm_ext/ecore_mmgen_ext.rb +4 -4
  7. data/lib/mmgen/templates/metamodel_generator.tpl +143 -143
  8. data/lib/rgen/ecore/ecore.rb +11 -1
  9. data/lib/rgen/ecore/ecore_interface.rb +47 -0
  10. data/lib/rgen/ecore/ecore_to_ruby.rb +166 -0
  11. data/lib/rgen/ecore/{ecore_transformer.rb → ruby_to_ecore.rb} +11 -11
  12. data/lib/rgen/environment.rb +15 -2
  13. data/lib/rgen/fragment/dump_file_cache.rb +63 -0
  14. data/lib/rgen/fragment/fragmented_model.rb +139 -0
  15. data/lib/rgen/fragment/model_fragment.rb +268 -0
  16. data/lib/rgen/instantiator/abstract_xml_instantiator.rb +44 -72
  17. data/lib/rgen/instantiator/default_xml_instantiator.rb +2 -2
  18. data/lib/rgen/instantiator/ecore_xml_instantiator.rb +16 -1
  19. data/lib/rgen/instantiator/json_instantiator.rb +16 -2
  20. data/lib/rgen/instantiator/nodebased_xml_instantiator.rb +118 -138
  21. data/lib/rgen/instantiator/qualified_name_resolver.rb +5 -1
  22. data/lib/rgen/instantiator/reference_resolver.rb +126 -24
  23. data/lib/rgen/instantiator/xmi11_instantiator.rb +6 -2
  24. data/lib/rgen/metamodel_builder.rb +18 -6
  25. data/lib/rgen/metamodel_builder/builder_extensions.rb +431 -407
  26. data/lib/rgen/metamodel_builder/builder_runtime.rb +8 -8
  27. data/lib/rgen/metamodel_builder/constant_order_helper.rb +4 -4
  28. data/lib/rgen/metamodel_builder/data_types.rb +5 -1
  29. data/lib/rgen/metamodel_builder/intermediate/feature.rb +167 -0
  30. data/lib/rgen/metamodel_builder/module_extension.rb +2 -2
  31. data/lib/rgen/model_builder.rb +10 -5
  32. data/lib/rgen/model_builder/builder_context.rb +17 -1
  33. data/lib/rgen/serializer/opposite_reference_filter.rb +18 -0
  34. data/lib/rgen/serializer/qualified_name_provider.rb +45 -0
  35. data/lib/rgen/template_language/template_container.rb +3 -1
  36. data/lib/rgen/{auto_class_creator.rb → util/auto_class_creator.rb} +6 -1
  37. data/lib/rgen/util/cached_glob.rb +67 -0
  38. data/lib/rgen/util/file_cache_map.rb +104 -0
  39. data/lib/rgen/util/file_change_detector.rb +78 -0
  40. data/lib/rgen/{method_delegation.rb → util/method_delegation.rb} +18 -3
  41. data/lib/rgen/{model_comparator.rb → util/model_comparator.rb} +17 -5
  42. data/lib/rgen/{model_comparator_base.rb → util/model_comparator_base.rb} +6 -1
  43. data/lib/rgen/{model_dumper.rb → util/model_dumper.rb} +6 -1
  44. data/lib/rgen/{name_helper.rb → util/name_helper.rb} +6 -1
  45. data/lib/rgen/util/pattern_matcher.rb +329 -0
  46. data/lib/transformers/uml13_to_ecore.rb +103 -60
  47. data/test/ecore_self_test.rb +43 -42
  48. data/test/json_test.rb +15 -0
  49. data/test/metamodel_builder_test.rb +361 -206
  50. data/test/metamodel_from_ecore_test.rb +45 -0
  51. data/test/metamodel_order_test.rb +10 -4
  52. data/test/metamodel_roundtrip_test.rb +2 -2
  53. data/test/metamodel_roundtrip_test/TestModel_Regenerated.rb +1 -1
  54. data/test/metamodel_roundtrip_test/houseMetamodel_Regenerated.ecore +50 -50
  55. data/test/method_delegation_test.rb +9 -9
  56. data/test/model_builder/ecore_internal.rb +19 -9
  57. data/test/model_builder/serializer_test.rb +1 -1
  58. data/test/reference_resolver_test.rb +79 -12
  59. data/test/rgen_test.rb +2 -0
  60. data/test/template_language_test.rb +7 -0
  61. data/test/template_language_test/templates/callback_indent_test/a.tpl +12 -0
  62. data/test/template_language_test/templates/callback_indent_test/b.tpl +5 -0
  63. data/test/testmodel/ea_testmodel_regenerated.xml +588 -583
  64. data/test/transformer_test.rb +3 -3
  65. data/test/util/file_cache_map_test.rb +91 -0
  66. data/test/util/file_cache_map_test/testdir/fileA +1 -0
  67. data/test/util_test.rb +4 -0
  68. data/test/xml_instantiator_test.rb +139 -135
  69. metadata +49 -104
  70. data/lib/rgen/ecore/ecore_instantiator.rb +0 -31
  71. data/lib/rgen/metamodel_builder/metamodel_description.rb +0 -232
  72. data/redist/xmlscan/ChangeLog +0 -1301
  73. data/redist/xmlscan/README +0 -34
  74. data/redist/xmlscan/THANKS +0 -11
  75. data/redist/xmlscan/doc/changes.html +0 -74
  76. data/redist/xmlscan/doc/changes.rd +0 -80
  77. data/redist/xmlscan/doc/en/conformance.html +0 -136
  78. data/redist/xmlscan/doc/en/conformance.rd +0 -152
  79. data/redist/xmlscan/doc/en/manual.html +0 -356
  80. data/redist/xmlscan/doc/en/manual.rd +0 -402
  81. data/redist/xmlscan/doc/ja/conformance.ja.html +0 -118
  82. data/redist/xmlscan/doc/ja/conformance.ja.rd +0 -134
  83. data/redist/xmlscan/doc/ja/manual.ja.html +0 -325
  84. data/redist/xmlscan/doc/ja/manual.ja.rd +0 -370
  85. data/redist/xmlscan/doc/src/Makefile +0 -41
  86. data/redist/xmlscan/doc/src/conformance.rd.src +0 -256
  87. data/redist/xmlscan/doc/src/langsplit.rb +0 -110
  88. data/redist/xmlscan/doc/src/manual.rd.src +0 -614
  89. data/redist/xmlscan/install.rb +0 -41
  90. data/redist/xmlscan/lib/xmlscan/encoding.rb +0 -311
  91. data/redist/xmlscan/lib/xmlscan/htmlscan.rb +0 -289
  92. data/redist/xmlscan/lib/xmlscan/namespace.rb +0 -352
  93. data/redist/xmlscan/lib/xmlscan/parser.rb +0 -299
  94. data/redist/xmlscan/lib/xmlscan/scanner.rb +0 -1109
  95. data/redist/xmlscan/lib/xmlscan/version.rb +0 -22
  96. data/redist/xmlscan/lib/xmlscan/visitor.rb +0 -158
  97. data/redist/xmlscan/lib/xmlscan/xmlchar.rb +0 -441
  98. data/redist/xmlscan/memo/CONFORMANCE +0 -1249
  99. data/redist/xmlscan/memo/PRODUCTIONS +0 -195
  100. data/redist/xmlscan/memo/contentspec.ry +0 -335
  101. data/redist/xmlscan/samples/chibixml.rb +0 -105
  102. data/redist/xmlscan/samples/getxmlchar.rb +0 -122
  103. data/redist/xmlscan/samples/rexml.rb +0 -159
  104. data/redist/xmlscan/samples/xmlbench.rb +0 -88
  105. data/redist/xmlscan/samples/xmlbench/parser/chibixml.rb +0 -22
  106. data/redist/xmlscan/samples/xmlbench/parser/nqxml.rb +0 -29
  107. data/redist/xmlscan/samples/xmlbench/parser/rexml.rb +0 -62
  108. data/redist/xmlscan/samples/xmlbench/parser/xmlparser.rb +0 -22
  109. data/redist/xmlscan/samples/xmlbench/parser/xmlscan-0.0.10.rb +0 -62
  110. data/redist/xmlscan/samples/xmlbench/parser/xmlscan-chibixml.rb +0 -22
  111. data/redist/xmlscan/samples/xmlbench/parser/xmlscan-rexml.rb +0 -22
  112. data/redist/xmlscan/samples/xmlbench/parser/xmlscan.rb +0 -99
  113. data/redist/xmlscan/samples/xmlbench/xmlbench-lib.rb +0 -116
  114. data/redist/xmlscan/samples/xmlconftest.rb +0 -200
  115. data/redist/xmlscan/test.rb +0 -7
  116. data/redist/xmlscan/tests/deftestcase.rb +0 -73
  117. data/redist/xmlscan/tests/runtest.rb +0 -47
  118. data/redist/xmlscan/tests/testall.rb +0 -14
  119. data/redist/xmlscan/tests/testencoding.rb +0 -438
  120. data/redist/xmlscan/tests/testhtmlscan.rb +0 -752
  121. data/redist/xmlscan/tests/testnamespace.rb +0 -457
  122. data/redist/xmlscan/tests/testparser.rb +0 -591
  123. data/redist/xmlscan/tests/testscanner.rb +0 -1749
  124. data/redist/xmlscan/tests/testxmlchar.rb +0 -143
  125. data/redist/xmlscan/tests/visitor.rb +0 -34
@@ -1,41 +0,0 @@
1
- #!/usr/bin/ruby
2
- #
3
- # install.rb
4
- #
5
- # $Id: install.rb,v 1.2 2002/12/26 21:09:38 katsu Exp $
6
-
7
- require 'rbconfig'
8
- require 'ftools'
9
- require 'find'
10
- require 'getoptlong'
11
-
12
- DEFAULT_DESTDIR = Config::CONFIG['sitelibdir'] || Config::CONFIG['sitedir']
13
- SRCDIR = File.dirname(__FILE__)
14
-
15
-
16
- def install_rb(from, to)
17
- from = SRCDIR + '/' + from
18
- Find.find(from) { |src|
19
- next unless File.file? src
20
- next unless /\.rb\z/ =~ src
21
- dst = src.sub(/\A#{Regexp.escape(from)}/, to)
22
- File.makedirs File.dirname(dst), true
23
- File.install src, dst, 0644, true
24
- }
25
- end
26
-
27
-
28
- destdir = DEFAULT_DESTDIR
29
- begin
30
- GetoptLong.new([ "-d", "--destdir", GetoptLong::REQUIRED_ARGUMENT ]
31
- ).each_option { |opt, arg|
32
- case opt
33
- when '-d' then
34
- destdir = arg
35
- end
36
- }
37
- rescue
38
- exit 2
39
- end
40
-
41
- install_rb "lib", destdir
@@ -1,311 +0,0 @@
1
- #
2
- # xmlscan/encoding.rb
3
- #
4
- # Copyright (C) Ueno Katsuhiro 2002
5
- #
6
- # $Id: encoding.rb,v 1.3 2003/01/12 04:10:33 katsu Exp $
7
- #
8
-
9
- require 'xmlscan/visitor'
10
-
11
-
12
- module XMLScan
13
-
14
- class EncodingError < Error ; end
15
-
16
-
17
- class Converter
18
-
19
- def initialize
20
- end
21
-
22
- def convert(s)
23
- s
24
- end
25
-
26
- def finish
27
- ''
28
- end
29
-
30
- end
31
-
32
-
33
-
34
- class SimpleConverter < Converter
35
-
36
- def SimpleConverter.new_class(block)
37
- Class.new(self).module_eval {
38
- define_method(:convert, block)
39
- self
40
- }
41
- end
42
-
43
- # checking for Module#define_method works
44
- begin
45
- Class.new.module_eval{define_method(:a){};self}.new.a
46
- rescue Exception
47
- class << SimpleConverter
48
- remove_method :new_class
49
- end
50
- def SimpleConverter.new_class(block)
51
- Class.new(self).module_eval {
52
- const_set :ConvProc, block
53
- module_eval "def convert(s) ; ConvProc.call s ; end"
54
- self
55
- }
56
- end
57
- end
58
-
59
- end
60
-
61
-
62
-
63
- class EncodingClass
64
-
65
- KCODE_None = //n.kcode
66
-
67
-
68
- class ConverterProperty
69
-
70
- def inspect
71
- "#<Conversion #{@from.name}:#{@to.name} #{@cost}>"
72
- end
73
-
74
- def initialize(from, to, cost, klass = nil)
75
- @from, @to, @cost, @klass = from, to, cost, klass
76
- end
77
-
78
- def new_converter
79
- @klass and @klass.new
80
- end
81
-
82
- attr_reader :from, :to, :cost
83
-
84
- end
85
-
86
-
87
- class EncodingProperty
88
-
89
- def inspect
90
- s = "#<Encoding #{@name}/#{@kcode}>"
91
- end
92
-
93
- def initialize(name)
94
- @name = name
95
- conv = ConverterProperty.new(self, self, 0)
96
- @converter = { self => conv }
97
- @convertable_from = { self => true }
98
- @kcode_map = {}
99
- end
100
-
101
- attr_reader :name, :kcode_map
102
-
103
-
104
- def convertable_from(encoding)
105
- @convertable_from[encoding] = true
106
- end
107
- protected :convertable_from
108
-
109
- def changed
110
- @convertable_from.each_key { |i| i.update_kcode_map }
111
- end
112
- private :changed
113
-
114
-
115
- def kcode?
116
- defined? @kcode
117
- end
118
-
119
- def kcode
120
- if defined? @kcode then
121
- @kcode
122
- else
123
- KCODE_None
124
- end
125
- end
126
-
127
- def kcode=(kcode)
128
- if defined? @kcode then
129
- raise EncodingError, "KCODE conflict" unless @kcode == kcode
130
- else
131
- @kcode = kcode
132
- changed
133
- end
134
- kcode
135
- end
136
-
137
-
138
- def converter(to)
139
- @converter[to]
140
- end
141
-
142
- def add_converter(to, cost, conv_class)
143
- if equal? to then
144
- raise EncodingError,"attempt to add a converter to the same encoding"
145
- end
146
- oldconv = @converter[to]
147
- if not oldconv or cost <= oldconv.cost then
148
- conv = ConverterProperty.new(self, to, cost, conv_class)
149
- @converter[to] = conv
150
- to.convertable_from self
151
- changed
152
- end
153
- nil
154
- end
155
-
156
-
157
- def update_kcode_map
158
- @kcode_map.clear
159
- @converter.each_value { |conv|
160
- k = conv.to.kcode
161
- if conv.to.kcode? and k then
162
- oldconv = @kcode_map[k]
163
- @kcode_map[k] = conv if not oldconv or conv.cost <= oldconv.cost
164
- end
165
- }
166
- end
167
- protected :update_kcode_map
168
-
169
- end
170
-
171
-
172
-
173
- def initialize
174
- @encoding = {}
175
- end
176
-
177
- class << self
178
- private :new
179
- attr_reader :instance
180
- end
181
- @instance = new
182
-
183
-
184
- private
185
-
186
- def get_encoding(name)
187
- encoding = @encoding[name.downcase]
188
- raise EncodingError, "undeclared encoding `#{name}'" unless encoding
189
- encoding
190
- end
191
-
192
- def touch_encoding(name)
193
- name = name.downcase
194
- encoding = @encoding[name]
195
- encoding = @encoding[name] = EncodingProperty.new(name) unless encoding
196
- encoding
197
- end
198
-
199
-
200
- public
201
-
202
- def alias(newname, oldname)
203
- newname = newname.downcase
204
- if @encoding.key? newname then
205
- raise EncodingError, "encoding `#{newname}' is already declared"
206
- end
207
- @encoding[newname] = get_encoding(oldname)
208
- nil
209
- end
210
-
211
-
212
- def kcode(name)
213
- encoding = @encoding[name.downcase]
214
- if encoding then
215
- encoding.kcode
216
- else
217
- KCODE_None
218
- end
219
- end
220
-
221
-
222
- def set_kcode(name, kcode)
223
- if kcode then
224
- kcode = Regexp.new('', nil, kcode).kcode
225
- else
226
- kcode = nil
227
- end
228
- touch_encoding(name).kcode = kcode
229
- end
230
-
231
-
232
- def add_converter(from, to, cost, conv_class = nil, &block)
233
- if block and conv_class then
234
- raise ArgumentError, "multiple converters given"
235
- elsif not block and not conv_class then
236
- raise ArgumentError, "no converter given"
237
- else
238
- block = conv_class if Proc === conv_class
239
- conv_class = SimpleConverter.new_class(block) if block
240
- end
241
- from = touch_encoding(from)
242
- to = touch_encoding(to)
243
- from.add_converter to, cost, conv_class
244
- end
245
-
246
-
247
- def converter(from, to)
248
- fromenc = get_encoding(from)
249
- toenc = get_encoding(to)
250
- conv = fromenc.converter(toenc)
251
- raise EncodingError, "can't convert `#{from}' to `#{to}'" unless conv
252
- conv.new_converter
253
- end
254
-
255
-
256
- def converter3(from, to = nil)
257
- to = from unless to
258
- fromenc = get_encoding(from)
259
- toenc = get_encoding(to)
260
- kcode_map = fromenc.kcode_map
261
- if kcode_map.empty? then
262
- if fromenc.kcode and fromenc.equal? toenc then
263
- return [ nil, fromenc.kcode, nil ]
264
- else
265
- raise EncodingError, "can't convert `#{from}' to any KCODE"
266
- end
267
- end
268
- mincost, minkcode, minconv = nil
269
- kcode_map.each { |kcode,conv|
270
- conv2 = conv.to.converter(toenc)
271
- if conv2 then
272
- cost = conv.cost + conv2.cost
273
- if not mincost or cost < mincost then
274
- mincost, minkcode, minconv = cost, kcode, conv
275
- end
276
- end
277
- }
278
- unless mincost then
279
- raise EncodingError, "can't convert `#{from}' to `#{to}' via any KCODE"
280
- end
281
- conv = minconv.new_converter
282
- conv2 = minconv.to.converter(toenc)
283
- conv2 = conv2 && conv2.new_converter
284
- [ conv, minkcode, conv2 ]
285
- end
286
-
287
- end
288
-
289
-
290
- Encoding = EncodingClass.instance
291
-
292
- Encoding.set_kcode 'utf-8', 'U'
293
- Encoding.set_kcode 'utf-16', nil
294
- Encoding.alias 'iso-10646-ucs-2', 'utf-16'
295
- Encoding.set_kcode 'iso-10646-ucs-4', nil
296
- Encoding.set_kcode 'iso-8859-1', 'N'
297
- Encoding.set_kcode 'iso-8859-2', 'N'
298
- Encoding.set_kcode 'iso-8859-3', 'N'
299
- Encoding.set_kcode 'iso-8859-4', 'N'
300
- Encoding.set_kcode 'iso-8859-5', 'N'
301
- Encoding.set_kcode 'iso-8859-6', 'N'
302
- Encoding.set_kcode 'iso-8859-7', 'N'
303
- Encoding.set_kcode 'iso-8859-8', 'N'
304
- Encoding.set_kcode 'iso-8859-9', 'N'
305
- Encoding.set_kcode 'iso-2022-jp', nil
306
- Encoding.set_kcode 'shift_jis', 'S'
307
- Encoding.set_kcode 'Windows-31J', 'S'
308
- Encoding.set_kcode 'euc-jp', 'E'
309
- Encoding.set_kcode 'euc-kr', 'E'
310
-
311
- end
@@ -1,289 +0,0 @@
1
- #
2
- # xmlscan/htmlscan.rb
3
- #
4
- # Copyright (C) Ueno Katsuhiro 2002
5
- #
6
- # $Id: htmlscan.rb,v 1.18 2003/05/01 15:36:50 katsu Exp $
7
- #
8
-
9
- require 'xmlscan/scanner'
10
-
11
-
12
- module XMLScan
13
-
14
- class HTMLScanner < XMLScanner
15
-
16
- private
17
-
18
- def wellformed_error(msg)
19
- # All wellformed error raised by XMLScanner are ignored.
20
- # XMLScanner only raises wellformed error in stan_stag, which is a
21
- # method completely overrided by HTMLScanner, so this method is
22
- # never called in fact.
23
- end
24
-
25
- def on_xmldecl
26
- raise "[BUG] this method must be never called"
27
- end
28
-
29
- def on_xmldecl_version(str)
30
- raise "[BUG] this method must be never called"
31
- end
32
-
33
- def on_xmldecl_encoding(str)
34
- raise "[BUG] this method must be never called"
35
- end
36
-
37
- def on_xmldecl_standalone(str)
38
- raise "[BUG] this method must be never called"
39
- end
40
-
41
- def on_xmldecl_other(name, value)
42
- raise "[BUG] this method must be never called"
43
- end
44
-
45
- def on_xmldecl_end
46
- raise "[BUG] this method must be never called"
47
- end
48
-
49
- def on_stag_end_empty(name)
50
- raise "[BUG] this method must be never called"
51
- end
52
-
53
-
54
- private
55
-
56
- def scan_comment(s)
57
- s[0,4] = '' # remove `<!--'
58
- comm = ''
59
- until /--/n =~ s
60
- comm << s
61
- s = @src.get_plain
62
- unless s then
63
- parse_error "unterminated comment meets EOF"
64
- return on_comment(comm)
65
- end
66
- end
67
- comm << $`
68
- s = $'
69
- until s.empty? || s.strip.empty? and @src.close_tag # --> or -- >
70
- comm << '--'
71
- if /\A\s*--/n =~ s then # <!--hoge-- --
72
- comm << $&
73
- s = $'
74
- if s.empty? and @src.close_tag then # <!--hoge-- -->
75
- parse_error "`-->' is found but comment must not end here"
76
- comm.chop!.chop!
77
- break
78
- end
79
- else # <!--hoge-- fuga
80
- parse_error "only whitespace can appear between two comments"
81
- end
82
- if /\A-\s*\z/n =~ s and @src.close_tag then # <!--hoge--->
83
- parse_error "`-->' is found but comment must not end here"
84
- comm.chop!
85
- break
86
- end
87
- until /--/n =~ s # copy & paste for performance
88
- comm << s
89
- s = @src.get_plain
90
- unless s then
91
- parse_error "unterminated comment meets EOF"
92
- return on_comment(comm)
93
- end
94
- end
95
- comm << $`
96
- s = $'
97
- end
98
- on_comment comm
99
- end
100
-
101
-
102
- alias scan_xml_pi scan_pi # PIO "<?" PIC "?>" -- <? PI ?> --
103
-
104
-
105
- def scan_pi(s) # <?PI > this is default in SGML.
106
- s[0,2] = '' # remove `<?'
107
- pi = s
108
- until @src.close_tag
109
- s = @src.get_plain
110
- unless s then
111
- parse_error "unterminated PI meets EOF"
112
- break
113
- end
114
- pi << s
115
- end
116
- on_pi '', pi
117
- end
118
-
119
-
120
- def scan_stag(s)
121
- unless /(?=[\/\s='"])/n =~ s then
122
- name = s
123
- name[0,1] = '' # remove `<'
124
- if name.empty? then # <> or <<
125
- if @src.close_tag then
126
- return found_empty_stag
127
- else
128
- parse_error "parse error at `<'"
129
- return on_chardata('<')
130
- end
131
- end
132
- on_stag name
133
- found_unclosed_stag name unless @src.close_tag
134
- on_stag_end name
135
- else
136
- name = $`
137
- s = $'
138
- name[0,1] = '' # remove `<'
139
- if name.empty? then # `< tag' or `<=`
140
- parse_error "parse error at `<'"
141
- if @src.close_tag then
142
- s << '>'
143
- end
144
- return on_chardata('<' << s)
145
- end
146
- on_stag name
147
- begin
148
- continue = false
149
- s.scan(
150
- /([^\s=\/'"]+)(?:\s*=\s*(?:('[^']*'?|"[^"]*"?)|([^\s='"]+)))?|(\S)/n
151
- ) { |key,val,val2,error|
152
- if key then
153
- if val then # key="value"
154
- on_attribute key
155
- qmark = val.slice!(0,1)
156
- if val[-1] == qmark[0] then
157
- val.chop!
158
- scan_attvalue val unless val.empty?
159
- else
160
- scan_attvalue val unless val.empty?
161
- begin
162
- s = @src.get
163
- unless s then
164
- parse_error "unterminated attribute `#{key}' meets EOF"
165
- break
166
- end
167
- c = s[0]
168
- val, s = s.split(qmark, 2)
169
- scan_attvalue '>' unless c == ?< or c == ?>
170
- scan_attvalue val if c
171
- end until s
172
- continue = s
173
- end
174
- on_attribute_end key
175
- elsif val2 then # key=value
176
- on_attribute key
177
- on_attr_value val2
178
- on_attribute_end key
179
- else # value
180
- on_attribute nil
181
- on_attr_value key
182
- on_attribute_end nil
183
- end
184
- else
185
- parse_error "parse error at `#{error}'"
186
- end
187
- }
188
- end while continue
189
- found_unclosed_stag name unless @src.close_tag
190
- on_stag_end name
191
- end
192
- end
193
-
194
-
195
- # This method should be called only from on_stag_end.
196
- def get_cdata_content
197
- unless not s = @src.test or s[0] == ?< && s[1] == ?/ then
198
- dst = @src.get
199
- until not s = @src.test or s[0] == ?< && s[1] == ?/
200
- dst << @src.get_plain
201
- end
202
- dst
203
- else
204
- ''
205
- end
206
- end
207
- public :get_cdata_content
208
-
209
-
210
- def scan_bang_tag(s)
211
- if s == '<!' and @src.close_tag then # <!>
212
- on_comment ''
213
- else
214
- parse_error "parse error at `<!'"
215
- while s and not @src.close_tag # skip entire
216
- s = @src.get_plain
217
- end
218
- end
219
- end
220
-
221
-
222
- def scan_internal_dtd(s)
223
- parse_error "DTD subset is found but it is not permitted in HTML"
224
- skip_internal_dtd s
225
- end
226
-
227
-
228
- def found_invalid_pubsys(pubsys)
229
- s = pubsys.upcase
230
- return s if s == 'PUBLIC' or s == 'SYSTEM'
231
- super
232
- end
233
-
234
-
235
- def scan_prolog(s)
236
- doctype = 0
237
- while s
238
- if s[0] == ?< then
239
- if (c = s[1]) == ?! then
240
- if s[2] == ?- and s[3] == ?- then
241
- scan_comment s
242
- elsif /\A<!doctype(?=\s)/in =~ s then
243
- doctype += 1
244
- if doctype > 1 then
245
- parse_error "another document type declaration is found"
246
- end
247
- scan_doctype $'
248
- else
249
- break
250
- end
251
- elsif c == ?? then
252
- scan_pi s
253
- else
254
- break
255
- end
256
- elsif s.strip.empty? then
257
- on_prolog_space s
258
- else
259
- break
260
- end
261
- s = @src.get
262
- end
263
- scan_content(s || @src.get)
264
- end
265
-
266
- end
267
-
268
- end
269
-
270
-
271
-
272
-
273
-
274
- if $0 == __FILE__ then
275
- class TestVisitor
276
- include XMLScan::Visitor
277
- def parse_error(msg)
278
- STDERR.printf("%s:%d: %s\n", $s.path, $s.lineno, msg) if $VERBOSE
279
- end
280
- end
281
-
282
- $s = scan = XMLScan::HTMLScanner.new(TestVisitor.new)
283
- src = ARGF
284
- def src.path; filename; end
285
- t1 = Time.times.utime
286
- scan.parse src
287
- t2 = Time.times.utime
288
- STDERR.printf "%2.3f sec\n", t2 - t1
289
- end