eim_xml 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -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