eim_xml 0.0.3
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.
- data/Rakefile +23 -0
- data/Rakefile.utirake +334 -0
- data/lib/eim_xml/assertions.rb +16 -0
- data/lib/eim_xml/dsl.rb +105 -0
- data/lib/eim_xml/formatter.rb +112 -0
- data/lib/eim_xml/matcher.rb +25 -0
- data/lib/eim_xml/parser.rb +87 -0
- data/lib/eim_xml/xhtml/dsl.rb +18 -0
- data/lib/eim_xml/xhtml.rb +135 -0
- data/lib/eim_xml.rb +210 -0
- data/spec/assertions_spec.rb +29 -0
- data/spec/dsl_spec.rb +217 -0
- data/spec/eim_xml_spec.rb +441 -0
- data/spec/formatter_spec.rb +215 -0
- data/spec/parser_spec.rb +102 -0
- data/spec/xhtml_spec.rb +490 -0
- metadata +82 -0
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
load "Rakefile.utirake"
|
2
|
+
UtiRake.setup do
|
3
|
+
rdoc do |t|
|
4
|
+
t.title = "Easy IMplemented XML"
|
5
|
+
t.main = "README"
|
6
|
+
t.rdoc_files.include(FileList["lib/**/*.rb", "README"])
|
7
|
+
end
|
8
|
+
|
9
|
+
gemspec do |s|
|
10
|
+
s.name = "eim_xml"
|
11
|
+
s.summary = "Easy IMplemented XML"
|
12
|
+
s.author = "KURODA Hiraku"
|
13
|
+
s.email = "hiraku@hinet.mydns.jp"
|
14
|
+
s.homepage = "http://eimxml.rubyforge.org/"
|
15
|
+
s.rubyforge_project = "eimxml"
|
16
|
+
end
|
17
|
+
|
18
|
+
publish("eimxml", "hiraku")
|
19
|
+
|
20
|
+
alias_task
|
21
|
+
end
|
22
|
+
|
23
|
+
task :default => :spec
|
data/Rakefile.utirake
ADDED
@@ -0,0 +1,334 @@
|
|
1
|
+
# Utility for Rake
|
2
|
+
#
|
3
|
+
# Copyright (C) 2008, KURODA Hiraku <hiraku@hinet.mydns.jp>
|
4
|
+
# You can redistribute it and/or modify it under GPL3.
|
5
|
+
|
6
|
+
require "rake/clean"
|
7
|
+
require "rake/testtask"
|
8
|
+
require "rake/rdoctask"
|
9
|
+
require "rake/gempackagetask"
|
10
|
+
require "rake/contrib/rubyforgepublisher"
|
11
|
+
require "rubygems/package_task"
|
12
|
+
|
13
|
+
class UtiRake
|
14
|
+
def self.setup(opt={}, &proc)
|
15
|
+
ur = new
|
16
|
+
ur.setup(opt, &proc)
|
17
|
+
rescue
|
18
|
+
puts $!.class, $!.message, $!.backtrace
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader :opt, :spec_proc, :cucumber_proc, :rdoc_proc, :gemspec_proc, :package_proc, :rcov_spec_proc
|
22
|
+
|
23
|
+
def setup(opt={}, &proc)
|
24
|
+
@opt = opt
|
25
|
+
directory "external"
|
26
|
+
CLOBBER << "external" << "coverage" << "coverage.spec" << "coverage.cuke" << "doc"
|
27
|
+
|
28
|
+
instance_eval(&proc) if proc
|
29
|
+
|
30
|
+
if need_spec?
|
31
|
+
require "spec/rake/spectask"
|
32
|
+
define_spec_task
|
33
|
+
end
|
34
|
+
|
35
|
+
if need_cucumber?
|
36
|
+
require "cucumber/rake/task"
|
37
|
+
define_cucumber_task
|
38
|
+
end
|
39
|
+
|
40
|
+
define_rdoc_task
|
41
|
+
define_rcov_task
|
42
|
+
define_package_task
|
43
|
+
define_here_dependency
|
44
|
+
define_alias_task if @alias_task
|
45
|
+
end
|
46
|
+
|
47
|
+
def need_spec?
|
48
|
+
File.directory?("spec")
|
49
|
+
end
|
50
|
+
|
51
|
+
def need_cucumber?
|
52
|
+
File.directory?("features")
|
53
|
+
end
|
54
|
+
|
55
|
+
def spec(&proc)
|
56
|
+
@spec_proc = proc
|
57
|
+
end
|
58
|
+
|
59
|
+
def cucumber(&proc)
|
60
|
+
@cucumber_proc = proc
|
61
|
+
end
|
62
|
+
|
63
|
+
def rdoc(&proc)
|
64
|
+
@rdoc_proc = proc
|
65
|
+
end
|
66
|
+
|
67
|
+
def gemspec(&proc)
|
68
|
+
@gemspec_proc = proc
|
69
|
+
end
|
70
|
+
|
71
|
+
def rcov_spec(&proc)
|
72
|
+
@rcov_spec_proc = proc
|
73
|
+
end
|
74
|
+
|
75
|
+
def package(&proc)
|
76
|
+
@package_proc = proc
|
77
|
+
end
|
78
|
+
|
79
|
+
def no_here(task)
|
80
|
+
@no_here_task = task
|
81
|
+
end
|
82
|
+
|
83
|
+
def no_here_task
|
84
|
+
@no_here_task || "spec:lump"
|
85
|
+
end
|
86
|
+
|
87
|
+
def alias_task
|
88
|
+
@alias_task = true
|
89
|
+
end
|
90
|
+
|
91
|
+
def hg(cmd)
|
92
|
+
sh "hg #{cmd.to_s}"
|
93
|
+
end
|
94
|
+
|
95
|
+
def external(base_url, *libs)
|
96
|
+
libs = libs.first if libs.first.is_a?(Array)
|
97
|
+
namespace :external do
|
98
|
+
directory "external/lib"
|
99
|
+
libs.each do |lib|
|
100
|
+
libdir = "external/#{lib}"
|
101
|
+
file libdir => "external/lib" do
|
102
|
+
if File.exist?("../#{lib}")
|
103
|
+
Dir.chdir("external") do
|
104
|
+
ln_s "../../#{lib}", "./", :force=>true
|
105
|
+
end
|
106
|
+
end
|
107
|
+
hg "clone #{File.join(base_url, lib)} #{libdir}" unless File.exist?(libdir)
|
108
|
+
Dir["#{libdir}/lib/*"].each do |f|
|
109
|
+
base = File.basename(f)
|
110
|
+
cd "external/lib" do
|
111
|
+
ln_s "../#{lib}/lib/#{base}", "./"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
if File.exist?(libdir)
|
117
|
+
Dir["#{libdir}/lib/*"].each do |f|
|
118
|
+
base = File.basename(f)
|
119
|
+
file "external/lib/#{base}" => "external/lib" do
|
120
|
+
cd "external/lib" do
|
121
|
+
ln_s "../#{lib}/lib/#{base}", "./"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
task :setup => "external/lib/#{base}"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
desc "Setup external libraries"
|
129
|
+
task :setup=>libdir
|
130
|
+
end
|
131
|
+
|
132
|
+
task :rake => :setup do
|
133
|
+
libs.each do |lib|
|
134
|
+
Dir.chdir "external/#{lib}" do
|
135
|
+
sh "rake"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
@external = true
|
141
|
+
end
|
142
|
+
|
143
|
+
def external?; @external; end
|
144
|
+
|
145
|
+
def define_rdoc_task
|
146
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
147
|
+
rdoc.options << "-S"
|
148
|
+
rdoc.options << "-w" << "3"
|
149
|
+
rdoc.options << "-c" << "UTF-8"
|
150
|
+
rdoc.rdoc_files.include("lib/**/*.rb")
|
151
|
+
rdoc_proc.call(rdoc) if rdoc_proc
|
152
|
+
end
|
153
|
+
task :doc do
|
154
|
+
remove_entry_secure "doc" if File.directory?("doc")
|
155
|
+
sh "rdoc -S -w 3 -c UTF-8 -d -x external"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def define_package_task
|
160
|
+
spec = Gem::Specification.new do |s|
|
161
|
+
s.platform = Gem::Platform::RUBY
|
162
|
+
s.files = FileList["Rakefile*", "lib/**/*", "spec/**/*"]
|
163
|
+
s.version = ENV["VER"] || "0.0.0.noversion"
|
164
|
+
gemspec_proc.call(s) if gemspec_proc
|
165
|
+
end
|
166
|
+
|
167
|
+
gem = Gem::PackageTask.new(spec) do |t|
|
168
|
+
t.need_tar_gz = true
|
169
|
+
t.need_zip = true
|
170
|
+
package_proc.call(t) if package_proc
|
171
|
+
end
|
172
|
+
|
173
|
+
task "utirake:gem" do
|
174
|
+
mv "Rakefile.utirake", "Rakefile.utirake_#{$$}"
|
175
|
+
symlink "external/utirake/utirake.rb", "Rakefile.utirake"
|
176
|
+
end
|
177
|
+
|
178
|
+
file "#{gem.package_dir}/#{gem.gem_spec.file_name}" => "utirake:gem"
|
179
|
+
|
180
|
+
task :gem do
|
181
|
+
rm "Rakefile.utirake"
|
182
|
+
mv "Rakefile.utirake_#{$$}", "Rakefile.utirake"
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def publish(project_name, user_id)
|
187
|
+
task :publish => "rdoc" do
|
188
|
+
yield if block_given
|
189
|
+
Rake::RubyForgePublisher.new(project_name, user_id).upload
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
FILE_SORT = lambda{|a, b| File.mtime(a)<=>File.mtime(b)}
|
194
|
+
|
195
|
+
def spec_files
|
196
|
+
@spec_files ||= FileList["./spec/**/*_spec.rb"].sort(&FILE_SORT).reverse
|
197
|
+
end
|
198
|
+
|
199
|
+
def set_spec_opts(spec)
|
200
|
+
spec.spec_opts << "-c"
|
201
|
+
spec.libs << "." << "./lib" << "./external/lib"
|
202
|
+
end
|
203
|
+
|
204
|
+
def define_spec_task
|
205
|
+
task :spec => "spec:apart"
|
206
|
+
namespace :spec do
|
207
|
+
spec_files.each do |f|
|
208
|
+
desc ""
|
209
|
+
Spec::Rake::SpecTask.new(:apart) do |s|
|
210
|
+
s.spec_files = FileList[f]
|
211
|
+
set_spec_opts(s)
|
212
|
+
spec_proc.call(s) if spec_proc
|
213
|
+
end
|
214
|
+
end
|
215
|
+
task(:apart).comment = "Run all specs separately"
|
216
|
+
|
217
|
+
desc "Run all specs in a lump"
|
218
|
+
Spec::Rake::SpecTask.new(:lump) do |s|
|
219
|
+
s.spec_files = spec_files
|
220
|
+
set_spec_opts(s)
|
221
|
+
spec_proc.call(s) if spec_proc
|
222
|
+
end
|
223
|
+
|
224
|
+
desc "Run all specs to profile"
|
225
|
+
Spec::Rake::SpecTask.new(:profile) do |s|
|
226
|
+
set_spec_opts(s)
|
227
|
+
s.spec_opts << "-f" << "profile"
|
228
|
+
end
|
229
|
+
|
230
|
+
`grep -sRn '#[[:space:]]*here[[:space:]]*$' spec`.split(/\n/).map{|l|
|
231
|
+
next nil unless l=~/\A(.*?):(\d+):/
|
232
|
+
[$1, $2.to_i]
|
233
|
+
}.compact.sort{|a, b| FILE_SORT.call(a[0], b[0])}.reverse.each do |file, line|
|
234
|
+
desc ""
|
235
|
+
Spec::Rake::SpecTask.new(:here) do |s|
|
236
|
+
s.spec_files = [file]
|
237
|
+
set_spec_opts(s)
|
238
|
+
s.spec_opts << "-l#{line}"
|
239
|
+
spec_proc.call(s) if spec_proc
|
240
|
+
end
|
241
|
+
end
|
242
|
+
task :no_here => no_here_task
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
def set_cucumber_opts(task)
|
247
|
+
task.libs << "."
|
248
|
+
cucumber_proc.call(task) if cucumber_proc
|
249
|
+
end
|
250
|
+
|
251
|
+
def define_cucumber_task
|
252
|
+
Cucumber::Rake::Task.new do |t|
|
253
|
+
set_cucumber_opts(t)
|
254
|
+
end
|
255
|
+
|
256
|
+
unless `grep -sRn '^[[:space:]]*@here$' features`.empty?
|
257
|
+
Cucumber::Rake::Task.new("cucumber:here") do |t|
|
258
|
+
t.cucumber_opts = %w[--tags @here]
|
259
|
+
set_cucumber_opts(t)
|
260
|
+
end
|
261
|
+
end
|
262
|
+
task "cucumber:no_here" => :cucumber
|
263
|
+
end
|
264
|
+
|
265
|
+
def define_here_dependency
|
266
|
+
unless Rake::Task.task_defined?("spec:here") || Rake::Task.task_defined?("cucumber:here")
|
267
|
+
task "spec:here" => "spec:no_here" if need_spec? && !Rake::Task.task_defined?("spec:here")
|
268
|
+
task "cucumber:here" => "cucumber:no_here" if need_cucumber? && !Rake::Task.task_defined?("cucumber:here")
|
269
|
+
end
|
270
|
+
|
271
|
+
task("spec:here").comment = "Run spec only marked '# here'"
|
272
|
+
task("cucumber:here").comment = "only tagged '@here'"
|
273
|
+
end
|
274
|
+
|
275
|
+
def rcov_opts(t, aggregation)
|
276
|
+
t.rcov_opts << "--exclude" << "gems\/,features\/,external\/"
|
277
|
+
t.rcov_opts << "--aggregate" << "coverage.data" if aggregation
|
278
|
+
t.rcov = true
|
279
|
+
end
|
280
|
+
|
281
|
+
def define_rcov_each_task(aggregation)
|
282
|
+
if need_spec?
|
283
|
+
Spec::Rake::SpecTask.new do |t|
|
284
|
+
t.spec_files = spec_files
|
285
|
+
rcov_opts(t, aggregation)
|
286
|
+
set_spec_opts(t)
|
287
|
+
rcov_spec_proc.call(t) if rcov_spec_proc
|
288
|
+
t.rcov_dir = "coverage.spec" unless aggregation
|
289
|
+
end
|
290
|
+
else
|
291
|
+
task "spec"
|
292
|
+
end
|
293
|
+
|
294
|
+
if need_cucumber?
|
295
|
+
Cucumber::Rake::Task.new do |t|
|
296
|
+
set_cucumber_opts(t)
|
297
|
+
rcov_opts(t, aggregation)
|
298
|
+
t.rcov_opts << "-o" << "coverage.cuke" unless aggregation
|
299
|
+
end
|
300
|
+
else
|
301
|
+
task "cucumber"
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
def define_rcov_task
|
306
|
+
namespace :rcov do
|
307
|
+
define_rcov_each_task(false)
|
308
|
+
end
|
309
|
+
|
310
|
+
desc "Run specs and Cucumber using RCov"
|
311
|
+
task "rcov:lump" do
|
312
|
+
rm "coverage.data" if File.exist?("coverage.data")
|
313
|
+
ns = namespace do
|
314
|
+
define_rcov_each_task(true)
|
315
|
+
end
|
316
|
+
ns.tasks.each do |t|
|
317
|
+
t.invoke
|
318
|
+
end
|
319
|
+
rm "coverage.data"
|
320
|
+
end
|
321
|
+
|
322
|
+
task "rcov:all" => %w[rcov:spec rcov:cucumber rcov:lump]
|
323
|
+
end
|
324
|
+
|
325
|
+
def define_alias_task
|
326
|
+
if Rake::Task.task_defined?("spec:apart")
|
327
|
+
task :apart => "spec:apart"
|
328
|
+
task :lump => "spec:lump"
|
329
|
+
task :here => "spec:here"
|
330
|
+
task :profile => "spec:profile"
|
331
|
+
end
|
332
|
+
task :here => "cucumber:here" if Rake::Task.task_defined?("cucumber:here")
|
333
|
+
end
|
334
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "eim_xml"
|
2
|
+
|
3
|
+
module EimXML::Assertions
|
4
|
+
def assert_has(expect, element, message="")
|
5
|
+
message << "\n" unless message.size==0
|
6
|
+
message << "<#{element}> doesn't have\n<#{expect.inspect}>"
|
7
|
+
assert_block(message) do
|
8
|
+
element.has?(expect)
|
9
|
+
end
|
10
|
+
rescue Test::Unit::AssertionFailedError=>e
|
11
|
+
bt = e.backtrace.find_all do |b|
|
12
|
+
b !~ /#{Regexp.escape(__FILE__)}/
|
13
|
+
end
|
14
|
+
raise Test::Unit::AssertionFailedError, e.message, bt
|
15
|
+
end
|
16
|
+
end
|
data/lib/eim_xml/dsl.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
# Easy IMplementation of XML
|
2
|
+
#
|
3
|
+
# Copyright (C) 2006,2008, KURODA Hiraku <hiraku@hinet.mydns.jp>
|
4
|
+
# You can redistribute it and/or modify it under GPL2.
|
5
|
+
#
|
6
|
+
|
7
|
+
require "eim_xml"
|
8
|
+
|
9
|
+
module EimXML
|
10
|
+
class BaseDSL
|
11
|
+
def add(v)
|
12
|
+
@_container << v
|
13
|
+
end
|
14
|
+
alias << add
|
15
|
+
|
16
|
+
def import_variables(src)
|
17
|
+
src.instance_variables.each do |v|
|
18
|
+
instance_variable_set(v, src.instance_variable_get(v)) unless v=~/\A@_[^_]/
|
19
|
+
end
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
def _build(klass, *arg, &proc)
|
24
|
+
e = klass.new(*arg)
|
25
|
+
@_container << e if @_container
|
26
|
+
if proc
|
27
|
+
oc = @_container
|
28
|
+
@_container = e
|
29
|
+
begin
|
30
|
+
instance_eval(&proc)
|
31
|
+
ensure
|
32
|
+
@_container = oc
|
33
|
+
end
|
34
|
+
end
|
35
|
+
e
|
36
|
+
end
|
37
|
+
private :_build
|
38
|
+
|
39
|
+
def _push(container)
|
40
|
+
oc = @_container
|
41
|
+
@_container = container
|
42
|
+
begin
|
43
|
+
yield if block_given?
|
44
|
+
container
|
45
|
+
ensure
|
46
|
+
@_container = oc
|
47
|
+
end
|
48
|
+
end
|
49
|
+
private :_push
|
50
|
+
|
51
|
+
def self.register(*args)
|
52
|
+
args.each do |klass, name|
|
53
|
+
name ||= klass.name.downcase[/(?:.*\:\:)?(.*)$/, 1]
|
54
|
+
eval("def #{name}(*a, &p);_build(#{klass}, *a, &p);end", binding)
|
55
|
+
eval("def self.#{name}(*a, &p);new.#{name}(*a, &p);end", binding)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class DSL < BaseDSL
|
61
|
+
end
|
62
|
+
|
63
|
+
class OpenDSL
|
64
|
+
def _build(klass, *arg, &proc)
|
65
|
+
e = klass.new(*arg)
|
66
|
+
oc = @_container
|
67
|
+
oc << e if oc.is_a?(Element)
|
68
|
+
@_container = e
|
69
|
+
begin
|
70
|
+
proc.call(self) if proc
|
71
|
+
e
|
72
|
+
ensure
|
73
|
+
@_container = oc
|
74
|
+
end
|
75
|
+
end
|
76
|
+
private :_build
|
77
|
+
|
78
|
+
def self.register_base(dsl, binding, *args)
|
79
|
+
args.each do |klass, name|
|
80
|
+
name ||= klass.name.downcase[/(?:.*\:\:)?(.*)$/, 1]
|
81
|
+
eval("def #{name}(*a, &p);_build(#{klass}, *a, &p);end", binding)
|
82
|
+
eval("def self.#{name}(*a, &p);self.new.#{name}(*a, &p);end", binding)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.register(*args)
|
87
|
+
register_base(self, binding, *args)
|
88
|
+
end
|
89
|
+
|
90
|
+
def initialize
|
91
|
+
@_container = nil
|
92
|
+
yield(self) if block_given?
|
93
|
+
end
|
94
|
+
|
95
|
+
def add(v)
|
96
|
+
@_container.add(v)
|
97
|
+
end
|
98
|
+
alias :<< :add
|
99
|
+
|
100
|
+
def container; @_container; end
|
101
|
+
end
|
102
|
+
|
103
|
+
DSL.register Element, Comment
|
104
|
+
OpenDSL.register Element, Comment
|
105
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require "eim_xml"
|
2
|
+
|
3
|
+
module EimXML
|
4
|
+
class Formatter
|
5
|
+
attr_reader :out
|
6
|
+
|
7
|
+
def self.write(element, opt={})
|
8
|
+
opt = {:out=>""}.merge(opt)
|
9
|
+
new(opt).write(element)
|
10
|
+
opt[:out]
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(opt)
|
14
|
+
@out = opt[:out]
|
15
|
+
@preservers = opt[:preservers]
|
16
|
+
@preserve_space = false
|
17
|
+
@indent_string = " "
|
18
|
+
@indent_depth = 0
|
19
|
+
end
|
20
|
+
|
21
|
+
def write(src)
|
22
|
+
case src
|
23
|
+
when Comment
|
24
|
+
write_comment(src)
|
25
|
+
when Element
|
26
|
+
write_element(src)
|
27
|
+
when PCString
|
28
|
+
write_pcstring(src)
|
29
|
+
else
|
30
|
+
write_string(src)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def indent(&proc)
|
35
|
+
@indent_depth += 1
|
36
|
+
proc.call
|
37
|
+
ensure
|
38
|
+
@indent_depth -= 1
|
39
|
+
end
|
40
|
+
|
41
|
+
def preserve_space_element?(elm)
|
42
|
+
@preservers && @preservers.any? do |e|
|
43
|
+
case e
|
44
|
+
when Symbol
|
45
|
+
e==elm.name
|
46
|
+
when Class
|
47
|
+
e===elm
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def write_indent
|
53
|
+
out << @indent_string*@indent_depth unless @preserve_space
|
54
|
+
end
|
55
|
+
|
56
|
+
def write_newline
|
57
|
+
out << "\n" unless @preserve_space
|
58
|
+
end
|
59
|
+
|
60
|
+
def write_comment(c)
|
61
|
+
write_indent
|
62
|
+
c.write_to(out)
|
63
|
+
write_newline
|
64
|
+
end
|
65
|
+
|
66
|
+
def write_contents_of(elm)
|
67
|
+
flag = @preserve_space
|
68
|
+
@preserve_space = true if preserve_space_element?(elm)
|
69
|
+
write_newline
|
70
|
+
indent do
|
71
|
+
elm.contents.each do |c|
|
72
|
+
write(c)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
write_indent
|
76
|
+
ensure
|
77
|
+
@preserve_space = flag
|
78
|
+
end
|
79
|
+
|
80
|
+
def write_element(elm)
|
81
|
+
write_indent
|
82
|
+
out << "<"
|
83
|
+
elm.name_and_attributes(out)
|
84
|
+
case elm.contents.size
|
85
|
+
when 0
|
86
|
+
out << " />"
|
87
|
+
write_newline
|
88
|
+
else
|
89
|
+
out << ">"
|
90
|
+
write_contents_of(elm)
|
91
|
+
out << "</#{elm.name}>"
|
92
|
+
write_newline
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def write_pcstring(pcs)
|
97
|
+
pcs.encoded_string.each_line do |l|
|
98
|
+
write_indent
|
99
|
+
out << l
|
100
|
+
end
|
101
|
+
write_newline
|
102
|
+
end
|
103
|
+
|
104
|
+
def write_string(str)
|
105
|
+
PCString.encode(str).each_line do |l|
|
106
|
+
write_indent
|
107
|
+
out << l
|
108
|
+
end
|
109
|
+
write_newline
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "eim_xml"
|
2
|
+
module EimXML::Matchers
|
3
|
+
class HaveContent
|
4
|
+
def initialize(expected)
|
5
|
+
@expected = expected
|
6
|
+
end
|
7
|
+
|
8
|
+
def matches?(target)
|
9
|
+
@target = target
|
10
|
+
@target.has?(@expected)
|
11
|
+
end
|
12
|
+
|
13
|
+
def failure_message
|
14
|
+
"expected #{@target.inspect} must have #{@expected}, but not."
|
15
|
+
end
|
16
|
+
|
17
|
+
def negative_failure_message
|
18
|
+
"expected #{@target.inspect} must not have #{@expected}, but has."
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def have(expected)
|
23
|
+
HaveContent.new(expected)
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# XML parser for EimXML
|
2
|
+
#
|
3
|
+
# Copyright (C) 2006, KURODA Hiraku <hiraku@hinet.mydns.jp>
|
4
|
+
# You can redistribute it and/or modify it under GPL2.
|
5
|
+
#
|
6
|
+
|
7
|
+
require "eim_xml"
|
8
|
+
require "strscan"
|
9
|
+
|
10
|
+
module EimXML
|
11
|
+
class ParseError < StandardError
|
12
|
+
end
|
13
|
+
|
14
|
+
class Parser
|
15
|
+
attr_reader :scanner
|
16
|
+
module RE
|
17
|
+
EMPTY_ELEMENT = /<([^>]*?)\/>/
|
18
|
+
START_TAG = /<([^>]*?([^\/>]\s*))>/
|
19
|
+
END_TAG = /<\/(\S+?)\s*>/
|
20
|
+
ATTRIBUTE = /\s+([^=\s]+)\s*=\s*('(.*?)'|"(.*?)")/m
|
21
|
+
STRING = /[^<]+/
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(src)
|
25
|
+
@scanner = StringScanner.new(src)
|
26
|
+
@scanner.scan(/\s*<\?.*?\?>\s*/)
|
27
|
+
end
|
28
|
+
|
29
|
+
def parse
|
30
|
+
if @scanner.scan(RE::EMPTY_ELEMENT)
|
31
|
+
parse_empty_element
|
32
|
+
elsif @scanner.scan(RE::START_TAG)
|
33
|
+
parse_start_tag
|
34
|
+
elsif @scanner.scan(RE::STRING)
|
35
|
+
parse_string
|
36
|
+
else
|
37
|
+
nil
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def parse_tag
|
42
|
+
s = StringScanner.new(@scanner[1])
|
43
|
+
e = Element.new(s.scan(/\S+/))
|
44
|
+
e[s[1]] = s[3] ? s[3] : s[4] while s.scan(RE::ATTRIBUTE)
|
45
|
+
e
|
46
|
+
end
|
47
|
+
protected :parse_tag
|
48
|
+
|
49
|
+
def parse_empty_element
|
50
|
+
parse_tag
|
51
|
+
end
|
52
|
+
protected :parse_empty_element
|
53
|
+
|
54
|
+
def parse_start_tag
|
55
|
+
e = parse_tag
|
56
|
+
|
57
|
+
until @scanner.scan(RE::END_TAG)
|
58
|
+
c = parse
|
59
|
+
raise ParseError.new("Syntax error.") unless c
|
60
|
+
e << c
|
61
|
+
end
|
62
|
+
raise ParseError.new("End tag mismatched.") unless @scanner[1].to_sym==e.name
|
63
|
+
e
|
64
|
+
end
|
65
|
+
protected :parse_start_tag
|
66
|
+
|
67
|
+
def parse_string
|
68
|
+
s = @scanner[0]
|
69
|
+
s = s.gsub(/&(amp|quot|apos|lt|gt);/) do
|
70
|
+
case $1
|
71
|
+
when "amp"
|
72
|
+
"&"
|
73
|
+
when "quot"
|
74
|
+
'"'
|
75
|
+
when "apos"
|
76
|
+
"'"
|
77
|
+
when "lt"
|
78
|
+
"<"
|
79
|
+
when "gt"
|
80
|
+
">"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
PCString.new(s)
|
84
|
+
end
|
85
|
+
protected :parse_string
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "eim_xml/dsl"
|
2
|
+
require "eim_xml/xhtml"
|
3
|
+
|
4
|
+
module EimXML::XHTML
|
5
|
+
class DSL < EimXML::BaseDSL
|
6
|
+
end
|
7
|
+
|
8
|
+
class OpenDSL < EimXML::OpenDSL
|
9
|
+
end
|
10
|
+
|
11
|
+
constants.each do |c|
|
12
|
+
v = const_get(c)
|
13
|
+
if v.is_a?(Class) && /_$/ !~ v.name
|
14
|
+
DSL.register v
|
15
|
+
OpenDSL.register v
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|