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 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