relevance-rcov 0.8.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,145 @@
1
+ # rcov Copyright (c) 2004-2006 Mauricio Fernandez <mfp@acm.org>
2
+ #
3
+ # See LEGAL and LICENSE for licensing information.
4
+
5
+ require 'rcov/version'
6
+
7
+ module Rcov
8
+
9
+ # RCOV__ performs the low-level tracing of the execution, gathering code
10
+ # coverage information in the process. The C core made available through the
11
+ # rcovrt extension will be used if possible. Otherwise the functionality
12
+ # will be emulated using set_trace_func, but this is very expensive and
13
+ # will fail if other libraries (e.g. breakpoint) change the trace_func.
14
+ #
15
+ # Do not use this module; it is very low-level and subject to frequent
16
+ # changes. Rcov::CodeCoverageAnalyzer offers a much more convenient and
17
+ # stable interface.
18
+ module RCOV__
19
+ COVER = {}
20
+ CALLSITES = {}
21
+ DEFSITES = {}
22
+ pure_ruby_impl_needed = true
23
+ unless defined? $rcov_do_not_use_rcovrt
24
+ begin
25
+ require 'rcovrt'
26
+ abi = [0,0,0]
27
+ begin
28
+ abi = RCOV__.ABI
29
+ raise if abi[0] != RCOVRT_ABI[0] || abi[1] < RCOVRT_ABI[1]
30
+ pure_ruby_impl_needed = false
31
+ rescue
32
+ $stderr.puts <<-EOF
33
+ The rcovrt extension I found was built for a different version of rcov.
34
+ The required ABI is: #{RCOVRT_ABI.join(".")}
35
+ Your current rcovrt extension is: #{abi.join(".")}
36
+
37
+ Please delete rcovrt.{so,bundle,dll,...} and install the required one.
38
+ EOF
39
+ raise LoadError
40
+ end
41
+ rescue LoadError
42
+ $stderr.puts <<-EOF
43
+
44
+ Since the rcovrt extension couldn't be loaded, rcov will run in pure-Ruby
45
+ mode, which is about two orders of magnitude slower.
46
+
47
+ If you're on win32, you can find a pre-built extension (usable with recent
48
+ One Click Installer and mswin32 builds) at http://eigenclass.org/hiki.rb?rcov .
49
+
50
+ EOF
51
+ end
52
+ end
53
+
54
+ if pure_ruby_impl_needed
55
+ methods = %w[install_coverage_hook remove_coverage_hook reset_coverage
56
+ install_callsite_hook remove_callsite_hook reset_callsite
57
+ generate_coverage_info generate_callsite_info]
58
+ sklass = class << self; self end
59
+ (methods & sklass.instance_methods).each do |meth|
60
+ sklass.class_eval{ remove_method meth }
61
+ end
62
+
63
+ @coverage_hook_activated = @callsite_hook_activated = false
64
+
65
+ def self.install_coverage_hook # :nodoc:
66
+ install_common_hook
67
+ @coverage_hook_activated = true
68
+ end
69
+
70
+ def self.install_callsite_hook # :nodoc:
71
+ install_common_hook
72
+ @callsite_hook_activated = true
73
+ end
74
+
75
+ def self.install_common_hook # :nodoc:
76
+ set_trace_func lambda {|event, file, line, id, binding, klass|
77
+ next unless SCRIPT_LINES__.has_key? file
78
+ case event
79
+ when 'call'
80
+ if @callsite_hook_activated
81
+ receiver = eval("self", binding)
82
+ klass = class << klass; self end unless klass === receiver
83
+ begin
84
+ DEFSITES[[klass.to_s, id.to_s]] = [file, line]
85
+ rescue Exception
86
+ end
87
+ caller_arr = self.format_backtrace_array(caller[1,1])
88
+ begin
89
+ hash = CALLSITES[[klass.to_s, id.to_s]] ||= {}
90
+ hash[caller_arr] ||= 0
91
+ hash[caller_arr] += 1
92
+ #puts "#{event} #{file} #{line} #{klass.inspect} " +
93
+ # "#{klass.object_id} #{id} #{eval('self', binding)}"
94
+ rescue Exception
95
+ end
96
+ end
97
+ when 'c-call', 'c-return', 'class'
98
+ return
99
+ end
100
+ if @coverage_hook_activated
101
+ COVER[file] ||= Array.new(SCRIPT_LINES__[file].size, 0)
102
+ COVER[file][line - 1] ||= 0
103
+ COVER[file][line - 1] += 1
104
+ end
105
+ }
106
+ end
107
+
108
+ def self.remove_coverage_hook # :nodoc:
109
+ @coverage_hook_activated = false
110
+ set_trace_func(nil) if !@callsite_hook_activated
111
+ end
112
+
113
+ def self.remove_callsite_hook # :nodoc:
114
+ @callsite_hook_activated = false
115
+ set_trace_func(nil) if !@coverage_hook_activated
116
+ end
117
+
118
+ def self.reset_coverage # :nodoc:
119
+ COVER.replace({})
120
+ end
121
+
122
+ def self.reset_callsite # :nodoc:
123
+ CALLSITES.replace({})
124
+ DEFSITES.replace({})
125
+ end
126
+
127
+ def self.generate_coverage_info # :nodoc:
128
+ Marshal.load(Marshal.dump(COVER))
129
+ end
130
+
131
+ def self.generate_callsite_info # :nodoc:
132
+ [CALLSITES, DEFSITES]
133
+ end
134
+
135
+ def self.format_backtrace_array(backtrace)
136
+ backtrace.map do |line|
137
+ md = /^([^:]*)(?::(\d+)(?::in `(.*)'))?/.match(line)
138
+ raise "Bad backtrace format" unless md
139
+ [nil, md[3] ? md[3].to_sym : nil, md[1], (md[2] || '').to_i]
140
+ end
141
+ end
142
+ end
143
+ end
144
+
145
+ end
@@ -0,0 +1,156 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Define a task library for performing code coverage analysis of unit tests
4
+ # using rcov.
5
+
6
+ require 'rake'
7
+ require 'rake/tasklib'
8
+
9
+ module Rcov
10
+
11
+ # Create a task that runs a set of tests through rcov, generating code
12
+ # coverage reports.
13
+ #
14
+ # Example:
15
+ #
16
+ # require 'rcov/rcovtask'
17
+ #
18
+ # Rcov::RcovTask.new do |t|
19
+ # t.libs << "test"
20
+ # t.test_files = FileList['test/test*.rb']
21
+ # t.verbose = true
22
+ # end
23
+ #
24
+ # If rake is invoked with a "TEST=filename" command line option,
25
+ # then the list of test files will be overridden to include only the
26
+ # filename specified on the command line. This provides an easy way
27
+ # to run just one test.
28
+ #
29
+ # If rake is invoked with a "RCOVOPTS=options" command line option,
30
+ # then the given options are passed to rcov.
31
+ #
32
+ # If rake is invoked with a "RCOVPATH=path/to/rcov" command line option,
33
+ # then the given rcov executable will be used; otherwise the one in your
34
+ # PATH will be used.
35
+ #
36
+ # Examples:
37
+ #
38
+ # rake rcov # run tests normally
39
+ # rake rcov TEST=just_one_file.rb # run just one test file.
40
+ # rake rcov RCOVOPTS="-p" # run in profile mode
41
+ # rake rcov RCOVOPTS="-T" # generate text report
42
+ #
43
+ class RcovTask < Rake::TaskLib
44
+
45
+ # Name of test task. (default is :rcov)
46
+ attr_accessor :name
47
+
48
+ # List of directories to added to $LOAD_PATH before running the
49
+ # tests. (default is 'lib')
50
+ attr_accessor :libs
51
+
52
+ # True if verbose test output desired. (default is false)
53
+ attr_accessor :verbose
54
+
55
+ # Request that the tests be run with the warning flag set.
56
+ # E.g. warning=true implies "ruby -w" used to run the tests.
57
+ attr_accessor :warning
58
+
59
+ # Glob pattern to match test files. (default is 'test/test*.rb')
60
+ attr_accessor :pattern
61
+
62
+ # Array of commandline options to pass to ruby when running the rcov loader.
63
+ attr_accessor :ruby_opts
64
+
65
+ # Array of commandline options to pass to rcov. An explicit
66
+ # RCOVOPTS=opts on the command line will override this. (default
67
+ # is <tt>["--text-report"]</tt>)
68
+ attr_accessor :rcov_opts
69
+
70
+ # Output directory for the XHTML report.
71
+ attr_accessor :output_dir
72
+
73
+ # Explicitly define the list of test files to be included in a
74
+ # test. +list+ is expected to be an array of file names (a
75
+ # FileList is acceptable). If both +pattern+ and +test_files+ are
76
+ # used, then the list of test files is the union of the two.
77
+ def test_files=(list)
78
+ @test_files = list
79
+ end
80
+
81
+ # Create a testing task.
82
+ def initialize(name=:rcov)
83
+ @name = name
84
+ @libs = ["lib"]
85
+ @pattern = nil
86
+ @test_files = nil
87
+ @verbose = false
88
+ @warning = false
89
+ @rcov_opts = ["--text-report"]
90
+ @ruby_opts = []
91
+ @output_dir = "coverage"
92
+ yield self if block_given?
93
+ @pattern = 'test/test*.rb' if @pattern.nil? && @test_files.nil?
94
+ define
95
+ end
96
+
97
+ # Create the tasks defined by this task lib.
98
+ def define
99
+ lib_path = @libs.join(File::PATH_SEPARATOR)
100
+ actual_name = Hash === name ? name.keys.first : name
101
+ unless Rake.application.last_comment
102
+ desc "Analyze code coverage with tests" +
103
+ (@name==:rcov ? "" : " for #{actual_name}")
104
+ end
105
+ task @name do
106
+ run_code = ''
107
+ RakeFileUtils.verbose(@verbose) do
108
+ run_code =
109
+ case rcov_path
110
+ when nil, ''
111
+ "-S rcov"
112
+ else %!"#{rcov_path}"!
113
+ end
114
+ ruby_opts = @ruby_opts.clone
115
+ ruby_opts.push( "-I#{lib_path}" )
116
+ ruby_opts.push run_code
117
+ ruby_opts.push( "-w" ) if @warning
118
+ ruby ruby_opts.join(" ") + " " + option_list +
119
+ %[ -o "#{@output_dir}" ] +
120
+ file_list.collect { |fn| %["#{fn}"] }.join(' ')
121
+ end
122
+ end
123
+
124
+ desc "Remove rcov products for #{actual_name}"
125
+ task paste("clobber_", actual_name) do
126
+ rm_r @output_dir rescue nil
127
+ end
128
+
129
+ clobber_task = paste("clobber_", actual_name)
130
+ task :clobber => [clobber_task]
131
+
132
+ task actual_name => clobber_task
133
+ self
134
+ end
135
+
136
+ def rcov_path # :nodoc:
137
+ ENV['RCOVPATH']
138
+ end
139
+
140
+ def option_list # :nodoc:
141
+ ENV['RCOVOPTS'] || @rcov_opts.join(" ") || ""
142
+ end
143
+
144
+ def file_list # :nodoc:
145
+ if ENV['TEST']
146
+ FileList[ ENV['TEST'] ]
147
+ else
148
+ result = []
149
+ result += @test_files.to_a if @test_files
150
+ result += FileList[ @pattern ].to_a if @pattern
151
+ FileList[result]
152
+ end
153
+ end
154
+ end
155
+ end
156
+
@@ -0,0 +1,71 @@
1
+ # rcov Copyright (c) 2004-2006 Mauricio Fernandez <mfp@acm.org>
2
+ # See LEGAL and LICENSE for additional licensing information.
3
+
4
+ require 'pathname'
5
+
6
+
7
+ module Rcov
8
+
9
+ # Try to fix bugs in the REXML shipped with Ruby 1.8.6
10
+ # They affect Mac OSX 10.5.1 users and motivates endless bug reports.
11
+ begin
12
+ require 'rexml/formatters/transitive'
13
+ require 'rexml/formatter/pretty'
14
+ rescue LoadError
15
+ end
16
+
17
+ require File.expand_path(File.join(File.dirname(__FILE__), 'rexml_extensions' ))
18
+
19
+ if (RUBY_VERSION == "1.8.6" || RUBY_VERSION == "1.8.7") && defined? REXML::Formatters::Transitive
20
+ class REXML::Document
21
+ remove_method :write rescue nil
22
+ def write( output=$stdout, indent=-1, trans=false, ie_hack=false )
23
+ if xml_decl.encoding != "UTF-8" && !output.kind_of?(Output)
24
+ output = Output.new( output, xml_decl.encoding )
25
+ end
26
+ formatter = if indent > -1
27
+ #if trans
28
+ REXML::Formatters::Transitive.new( indent )
29
+ #else
30
+ # REXML::Formatters::Pretty.new( indent, ie_hack )
31
+ #end
32
+ else
33
+ REXML::Formatters::Default.new( ie_hack )
34
+ end
35
+ formatter.write( self, output )
36
+ end
37
+ end
38
+
39
+ class REXML::Formatters::Transitive
40
+ remove_method :write_element rescue nil
41
+ def write_element( node, output )
42
+ output << "<#{node.expanded_name}"
43
+
44
+ node.attributes.each_attribute do |attr|
45
+ output << " "
46
+ attr.write( output )
47
+ end unless node.attributes.empty?
48
+
49
+ if node.children.empty?
50
+ output << "/>"
51
+ else
52
+ output << ">"
53
+ # If compact and all children are text, and if the formatted output
54
+ # is less than the specified width, then try to print everything on
55
+ # one line
56
+ skip = false
57
+ @level += @indentation
58
+ node.children.each { |child|
59
+ write( child, output )
60
+ }
61
+ @level -= @indentation
62
+ output << "</#{node.expanded_name}>"
63
+ end
64
+ output << "\n"
65
+ output << ' '*@level
66
+ end
67
+ end
68
+
69
+ end
70
+
71
+ end
@@ -0,0 +1,44 @@
1
+ require 'rexml/document'
2
+ require 'rexml/formatters/pretty'
3
+
4
+ module Rcov
5
+ module REXMLExtensions
6
+
7
+ def self.fix_pretty_formatter_wrap
8
+ REXML::Formatters::Pretty.class_eval do
9
+ include PrettyFormatterWrapFix
10
+ end
11
+ end
12
+
13
+ # Fix for this bug: http://clint-hill.com/2008/10/02/a-bug-in-ruby-did-i-just-find-that/
14
+ # Also known from this fun exception:
15
+ #
16
+ # /usr/local/ruby/lib/ruby/1.8/rexml/formatters/pretty.rb:131:in
17
+ # `[]': no implicit conversion from nil to integer (TypeError)
18
+ #
19
+ # This bug was fixed in Ruby with this changeset http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=19487
20
+ # ...which should mean that this bug only affects Ruby 1.8.6. The latest stable version of 1.8.7 (and up) should be fine.
21
+ module PrettyFormatterWrapFix
22
+
23
+ def self.included(base)
24
+ base.class_eval do
25
+ def wrap(string, width)
26
+ # Recursively wrap string at width.
27
+ return string if string.length <= width
28
+ place = string.rindex(' ', width) # Position in string with last ' ' before cutoff
29
+ return string if place.nil?
30
+ return string[0,place] + "\n" + wrap(string[place+1..-1], width)
31
+ end
32
+ end
33
+ end
34
+
35
+ end
36
+
37
+ def self.init!
38
+ if RUBY_VERSION == "1.8.6"
39
+ fix_pretty_formatter_wrap
40
+ end
41
+ end
42
+ end
43
+
44
+ end
@@ -0,0 +1,11 @@
1
+ # rcov Copyright (c) 2004-2006 Mauricio Fernandez <mfp@acm.org>
2
+ #
3
+ # See LEGAL and LICENSE for licensing information.
4
+
5
+ module Rcov
6
+ VERSION = "0.8.2.1"
7
+ RELEASE_DATE = "2009-03-17"
8
+ RCOVRT_ABI = [2,0,0]
9
+ UPSTREAM_URL = "http://github.com/spicycode/rcov"
10
+
11
+ end
@@ -0,0 +1,754 @@
1
+ # xx can be redistributed and used under the following conditions
2
+ # (just keep the following copyright notice, list of conditions and disclaimer
3
+ # in order to satisfy rcov's "Ruby license" and xx's license simultaneously).
4
+ #
5
+ #ePark Labs Public License version 1
6
+ #Copyright (c) 2005, ePark Labs, Inc. and contributors
7
+ #All rights reserved.
8
+ #
9
+ #Redistribution and use in source and binary forms, with or without modification,
10
+ #are permitted provided that the following conditions are met:
11
+ #
12
+ # 1. Redistributions of source code must retain the above copyright notice, this
13
+ # list of conditions and the following disclaimer.
14
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
15
+ # this list of conditions and the following disclaimer in the documentation
16
+ # and/or other materials provided with the distribution.
17
+ # 3. Neither the name of ePark Labs nor the names of its contributors may be
18
+ # used to endorse or promote products derived from this software without
19
+ # specific prior written permission.
20
+ #
21
+ #THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22
+ #ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23
+ #WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24
+ #DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
25
+ #ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26
+ #(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27
+ #LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
28
+ #ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29
+ #(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30
+ #SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
+
32
+ unless defined? $__xx_rb__
33
+
34
+ require "rexml/document"
35
+
36
+
37
+ module XX
38
+
39
+ VERSION = "0.1.0"
40
+
41
+ %w(
42
+ CRAZY_LIKE_A_HELL
43
+ PERMISSIVE
44
+ STRICT
45
+ ANY
46
+ ).each{|c| const_set c, c}
47
+
48
+ class Document
49
+
50
+ attr "doc"
51
+ attr "stack"
52
+ attr "size"
53
+
54
+ def initialize(*a, &b)
55
+ @doc = ::REXML::Document::new(*a, &b)
56
+ @stack = [@doc]
57
+ @size = 0
58
+ end
59
+
60
+ def top
61
+ @stack.last
62
+ end
63
+
64
+ def push(element)
65
+ @stack.push element
66
+ end
67
+
68
+ def pop
69
+ @stack.pop unless @stack.size == 1
70
+ end
71
+
72
+ def tracking_additions
73
+ n = @size
74
+ yield
75
+ return @size - n
76
+ end
77
+
78
+ def to_str(port = "")
79
+ @doc.write port, indent=-1, transitive=false, ie_hack=true
80
+ port
81
+ end
82
+
83
+ alias_method "to_s", "to_str"
84
+
85
+ def pretty(port = '')
86
+ @doc.write port, indent=2, transitive=false, ie_hack=true
87
+ port
88
+ end
89
+
90
+ def create(element)
91
+ push element
92
+ begin
93
+ object = nil
94
+ additions =
95
+ tracking_additions do
96
+ object = yield element if block_given?
97
+ end
98
+ if object and additions.zero?
99
+ self << object
100
+ end
101
+ ensure
102
+ pop
103
+ end
104
+ self << element
105
+ element
106
+
107
+ end
108
+ def << object
109
+
110
+ t, x = top, object
111
+
112
+ if x
113
+ case t
114
+ when ::REXML::Document
115
+
116
+ begin
117
+ t <<
118
+ case x
119
+ when ::REXML::Document
120
+ x.root || ::REXML::Text::new(x.to_s)
121
+ when ::REXML::Element
122
+ x
123
+ when ::REXML::CData
124
+ x
125
+ when ::REXML::Text
126
+ x
127
+ else # string
128
+ ::REXML::Text::new(x.to_s)
129
+ end
130
+ rescue
131
+ if t.respond_to? "root"
132
+ t = t.root
133
+ retry
134
+ else
135
+ raise
136
+ end
137
+ end
138
+
139
+ when ::REXML::Element
140
+ t <<
141
+ case x
142
+ when ::REXML::Document
143
+ x.root || ::REXML::Text::new(x.to_s)
144
+ when ::REXML::Element
145
+ x
146
+ when ::REXML::CData
147
+ #::REXML::Text::new(x.write(""))
148
+ x
149
+ when ::REXML::Text
150
+ x
151
+ else # string
152
+ ::REXML::Text::new(x.to_s)
153
+ end
154
+
155
+ when ::REXML::Text
156
+ t <<
157
+ case x
158
+ when ::REXML::Document
159
+ x.write ""
160
+ when ::REXML::Element
161
+ x.write ""
162
+ when ::REXML::CData
163
+ x.write ""
164
+ when ::REXML::Text
165
+ x.write ""
166
+ else # string
167
+ x.to_s
168
+ end
169
+
170
+ else # other - try anyhow
171
+ t <<
172
+ case x
173
+ when ::REXML::Document
174
+ x.write ""
175
+ when ::REXML::Element
176
+ x.write ""
177
+ when ::REXML::CData
178
+ x.write ""
179
+ when ::REXML::Text
180
+ x.write ""
181
+ else # string
182
+ x.to_s
183
+ end
184
+ end
185
+ end
186
+
187
+ @size += 1
188
+ self
189
+
190
+ end
191
+
192
+ end
193
+
194
+ module Markup
195
+
196
+ class Error < ::StandardError; end
197
+
198
+ module InstanceMethods
199
+
200
+ def method_missing m, *a, &b
201
+
202
+ m = m.to_s
203
+
204
+ tag_method, tag_name = xx_class::xx_tag_method_name m
205
+
206
+ c_method_missing = xx_class::xx_config_for "method_missing", xx_which
207
+ c_tags = xx_class::xx_config_for "tags", xx_which
208
+
209
+ pat =
210
+ case c_method_missing
211
+ when ::XX::CRAZY_LIKE_A_HELL
212
+ %r/.*/
213
+ when ::XX::PERMISSIVE
214
+ %r/_$/o
215
+ when ::XX::STRICT
216
+ %r/_$/o
217
+ else
218
+ super(m.to_sym, *a, &b)
219
+ end
220
+
221
+ super(m.to_sym, *a, &b) unless m =~ pat
222
+
223
+ if c_method_missing == ::XX::STRICT
224
+ super(m.to_sym, *a, &b) unless c_tags.include? tag_name
225
+ end
226
+
227
+ ret, defined = nil
228
+
229
+ begin
230
+ xx_class::xx_define_tmp_method tag_method
231
+ xx_class::xx_define_tag_method tag_method, tag_name
232
+ ret = send tag_method, *a, &b
233
+ defined = true
234
+ ensure
235
+ xx_class::xx_remove_tag_method tag_method unless defined
236
+ end
237
+
238
+ ret
239
+
240
+ end
241
+ def xx_tag_ tag_name, *a, &b
242
+
243
+ tag_method, tag_name = xx_class::xx_tag_method_name tag_name
244
+
245
+ ret, defined = nil
246
+
247
+ begin
248
+ xx_class::xx_define_tmp_method tag_method
249
+ xx_class::xx_define_tag_method tag_method, tag_name
250
+ ret = send tag_method, *a, &b
251
+ defined = true
252
+ ensure
253
+ xx_class::xx_remove_tag_method tag_method unless defined
254
+ end
255
+
256
+ ret
257
+
258
+ end
259
+ alias_method "g_", "xx_tag_"
260
+ def xx_which *argv
261
+
262
+ @xx_which = nil unless defined? @xx_which
263
+ if argv.empty?
264
+ @xx_which
265
+ else
266
+ xx_which = @xx_which
267
+ begin
268
+ @xx_which = argv.shift
269
+ return yield
270
+ ensure
271
+ @xx_which = xx_which
272
+ end
273
+ end
274
+
275
+ end
276
+ def xx_with_doc_in_effect *a, &b
277
+
278
+ @xx_docs ||= []
279
+ doc = ::XX::Document::new(*a)
280
+ ddoc = doc.doc
281
+ begin
282
+ @xx_docs.push doc
283
+ b.call doc if b
284
+
285
+ doctype = xx_config_for "doctype", xx_which
286
+ if doctype
287
+ unless ddoc.doctype
288
+ doctype = ::REXML::DocType::new doctype unless
289
+ ::REXML::DocType === doctype
290
+ ddoc << doctype
291
+ end
292
+ end
293
+
294
+ xmldecl = xx_config_for "xmldecl", xx_which
295
+ if xmldecl
296
+ if ddoc.xml_decl == ::REXML::XMLDecl::default
297
+ xmldecl = ::REXML::XMLDecl::new xmldecl unless
298
+ ::REXML::XMLDecl === xmldecl
299
+ ddoc << xmldecl
300
+ end
301
+ end
302
+
303
+ return doc
304
+ ensure
305
+ @xx_docs.pop
306
+ end
307
+
308
+ end
309
+ def xx_doc
310
+
311
+ @xx_docs.last rescue raise "no xx_doc in effect!"
312
+
313
+ end
314
+ def xx_text_ *objects, &b
315
+
316
+ doc = xx_doc
317
+
318
+ text =
319
+ ::REXML::Text::new("",
320
+ respect_whitespace=true, parent=nil
321
+ )
322
+
323
+ objects.each do |object|
324
+ text << object.to_s if object
325
+ end
326
+
327
+ doc.create text, &b
328
+
329
+ end
330
+ alias_method "text_", "xx_text_"
331
+ alias_method "t_", "xx_text_"
332
+ def xx_markup_ *objects, &b
333
+
334
+ doc = xx_doc
335
+
336
+ doc2 = ::REXML::Document::new ""
337
+
338
+ objects.each do |object|
339
+ (doc2.root ? doc2.root : doc2) << ::REXML::Document::new(object.to_s)
340
+ end
341
+
342
+
343
+ ret = doc.create doc2, &b
344
+ puts doc2.to_s
345
+ STDIN.gets
346
+ ret
347
+
348
+ end
349
+ alias_method "x_", "xx_markup_"
350
+ def xx_any_ *objects, &b
351
+
352
+ doc = xx_doc
353
+ nothing = %r/.^/m
354
+
355
+ text =
356
+ ::REXML::Text::new("",
357
+ respect_whitespace=true, parent=nil, raw=true, entity_filter=nil, illegal=nothing
358
+ )
359
+
360
+ objects.each do |object|
361
+ text << object.to_s if object
362
+ end
363
+
364
+ doc.create text, &b
365
+
366
+ end
367
+ alias_method "h_", "xx_any_"
368
+ remove_method "x_" if instance_methods.include? "x_"
369
+ alias_method "x_", "xx_any_" # supplant for now
370
+ def xx_cdata_ *objects, &b
371
+
372
+ doc = xx_doc
373
+
374
+ cdata = ::REXML::CData::new ""
375
+
376
+ objects.each do |object|
377
+ cdata << object.to_s if object
378
+ end
379
+
380
+ doc.create cdata, &b
381
+
382
+ end
383
+ alias_method "c_", "xx_cdata_"
384
+ def xx_parse_attributes string
385
+
386
+ string = string.to_s
387
+ tokens = string.split %r/,/o
388
+ tokens.map{|t| t.sub!(%r/[^=]+=/){|key_eq| key_eq.chop << " : "}}
389
+ xx_parse_yaml_attributes(tokens.join(','))
390
+
391
+ end
392
+ alias_method "att_", "xx_parse_attributes"
393
+ def xx_parse_yaml_attributes string
394
+
395
+ require "yaml"
396
+ string = string.to_s
397
+ string = "{" << string unless string =~ %r/^\s*[{]/o
398
+ string = string << "}" unless string =~ %r/[}]\s*$/o
399
+ obj = ::YAML::load string
400
+ raise ArgumentError, "<#{ obj.class }> not Hash!" unless Hash === obj
401
+ obj
402
+
403
+ end
404
+ alias_method "at_", "xx_parse_yaml_attributes"
405
+ alias_method "yat_", "xx_parse_yaml_attributes"
406
+ def xx_class
407
+
408
+ @xx_class ||= self.class
409
+
410
+ end
411
+ def xx_tag_method_name *a, &b
412
+
413
+ xx_class.xx_tag_method_name(*a, &b)
414
+
415
+ end
416
+ def xx_define_tmp_method *a, &b
417
+
418
+ xx_class.xx_define_tmp_methodr(*a, &b)
419
+
420
+ end
421
+ def xx_define_tag_method *a, &b
422
+
423
+ xx_class.xx_define_tag_method(*a, &b)
424
+
425
+ end
426
+ def xx_remove_tag_method *a, &b
427
+
428
+ xx_class.xx_tag_remove_method(*a, &b)
429
+
430
+ end
431
+ def xx_ancestors
432
+
433
+ raise Error, "no xx_which in effect" unless xx_which
434
+ xx_class.xx_ancestors xx_which
435
+
436
+ end
437
+ def xx_config
438
+
439
+ xx_class.xx_config
440
+
441
+ end
442
+ def xx_config_for *a, &b
443
+
444
+ xx_class.xx_config_for(*a, &b)
445
+
446
+ end
447
+ def xx_configure *a, &b
448
+
449
+ xx_class.xx_configure(*a, &b)
450
+
451
+ end
452
+
453
+ end
454
+
455
+ module ClassMethods
456
+
457
+ def xx_tag_method_name m
458
+
459
+ m = m.to_s
460
+ tag_method, tag_name = m, m.gsub(%r/_+$/, "")
461
+ [ tag_method, tag_name ]
462
+
463
+ end
464
+ def xx_define_tmp_method m
465
+
466
+ define_method(m){ raise NotImplementedError, m.to_s }
467
+
468
+ end
469
+ def xx_define_tag_method tag_method, tag_name = nil
470
+
471
+ tag_method = tag_method.to_s
472
+ tag_name ||= tag_method.gsub %r/_+$/, ""
473
+
474
+ remove_method tag_method if instance_methods.include? tag_method
475
+ module_eval <<-code, __FILE__, __LINE__+1
476
+ def #{ tag_method } *a, &b
477
+ hashes, nothashes = a.partition{|x| Hash === x}
478
+
479
+ doc = xx_doc
480
+ element = ::REXML::Element::new '#{ tag_name }'
481
+
482
+ hashes.each{|h| h.each{|k,v| element.add_attribute k.to_s, v}}
483
+ nothashes.each{|nh| element << ::REXML::Text::new(nh.to_s)}
484
+
485
+ doc.create element, &b
486
+ end
487
+ code
488
+ tag_method
489
+
490
+ end
491
+ def xx_remove_tag_method tag_method
492
+
493
+ remove_method tag_method rescue nil
494
+
495
+ end
496
+ def xx_ancestors xx_which = self
497
+
498
+ list = []
499
+ ancestors.each do |a|
500
+ list << a if a < xx_which
501
+ end
502
+ xx_which.ancestors.each do |a|
503
+ list << a if a <= Markup
504
+ end
505
+ list
506
+
507
+ end
508
+ def xx_config
509
+
510
+ @@xx_config ||= Hash::new{|h,k| h[k] = {}}
511
+
512
+ end
513
+ def xx_config_for key, xx_which = nil
514
+
515
+ key = key.to_s
516
+ xx_which ||= self
517
+ xx_ancestors(xx_which).each do |a|
518
+ if xx_config[a].has_key? key
519
+ return xx_config[a][key]
520
+ end
521
+ end
522
+ nil
523
+
524
+ end
525
+ def xx_configure key, value, xx_which = nil
526
+
527
+ key = key.to_s
528
+ xx_which ||= self
529
+ xx_config[xx_which][key] = value
530
+
531
+ end
532
+
533
+ end
534
+
535
+ extend ClassMethods
536
+ include InstanceMethods
537
+
538
+ def self::included other, *a, &b
539
+
540
+ ret = super
541
+ other.module_eval do
542
+ include Markup::InstanceMethods
543
+ extend Markup::ClassMethods
544
+ class << self
545
+ define_method("included", Markup::XX_MARKUP_RECURSIVE_INCLUSION_PROC)
546
+ end
547
+ end
548
+ ret
549
+
550
+ end
551
+ XX_MARKUP_RECURSIVE_INCLUSION_PROC = method("included").to_proc
552
+
553
+ xx_configure "method_missing", XX::PERMISSIVE
554
+ xx_configure "tags", []
555
+ xx_configure "doctype", nil
556
+ xx_configure "xmldecl", nil
557
+
558
+ end
559
+
560
+ module XHTML
561
+
562
+ include Markup
563
+ xx_configure "doctype", %(html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd")
564
+
565
+ def xhtml_ which = XHTML, *a, &b
566
+
567
+ xx_which(which) do
568
+ doc = xx_with_doc_in_effect(*a, &b)
569
+ ddoc = doc.doc
570
+ root = ddoc.root
571
+ if root and root.name and root.name =~ %r/^html$/i
572
+ if root.attribute("lang",nil).nil? or root.attribute("lang",nil).to_s.empty?
573
+ root.add_attribute "lang", "en"
574
+ end
575
+ if root.attribute("xml:lang").nil? or root.attribute("xml:lang").to_s.empty?
576
+ root.add_attribute "xml:lang", "en"
577
+ end
578
+ if root.namespace.nil? or root.namespace.to_s.empty?
579
+ root.add_namespace "http://www.w3.org/1999/xhtml"
580
+ end
581
+ end
582
+ doc
583
+ end
584
+
585
+ end
586
+
587
+ module Strict
588
+
589
+ include XHTML
590
+ xx_configure "doctype", %(html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd")
591
+ xx_configure "tags", %w(
592
+ html head body div span DOCTYPE title link meta style p
593
+ h1 h2 h3 h4 h5 h6 strong em abbr acronym address bdo blockquote cite q code
594
+ ins del dfn kbd pre samp var br a base img
595
+ area map object param ul ol li dl dt dd table
596
+ tr td th tbody thead tfoot col colgroup caption form input
597
+ textarea select option optgroup button label fieldset legend script noscript b
598
+ i tt sub sup big small hr
599
+ )
600
+ xx_configure "method_missing", ::XX::STRICT
601
+
602
+ def xhtml_ which = XHTML::Strict, *a, &b
603
+
604
+ super(which, *a, &b)
605
+
606
+ end
607
+
608
+ end
609
+
610
+ module Transitional
611
+
612
+ include XHTML
613
+ xx_configure "doctype", %(html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd")
614
+ def xhtml_ which = XHTML::Transitional, *a, &b
615
+
616
+ super(which, *a, &b)
617
+
618
+ end
619
+
620
+ end
621
+
622
+ end
623
+
624
+ module HTML4
625
+
626
+ include Markup
627
+ xx_configure "doctype", %(html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN")
628
+
629
+ def html4_ which = HTML4, *a, &b
630
+
631
+ xx_which(which){ xx_with_doc_in_effect(*a, &b) }
632
+
633
+ end
634
+
635
+ module Strict
636
+
637
+ include HTML4
638
+ xx_configure "doctype", %(html PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN")
639
+ xx_configure "tags", %w(
640
+ html head body div span DOCTYPE title link meta style p
641
+ h1 h2 h3 h4 h5 h6 strong em abbr acronym address bdo blockquote cite q code
642
+ ins del dfn kbd pre samp var br a base img
643
+ area map object param ul ol li dl dt dd table
644
+ tr td th tbody thead tfoot col colgroup caption form input
645
+ textarea select option optgroup button label fieldset legend script noscript b
646
+ i tt sub sup big small hr
647
+ )
648
+ xx_configure "method_missing", ::XX::STRICT
649
+ def html4_ which = HTML4::Strict, *a, &b
650
+
651
+ super(which, *a, &b)
652
+
653
+ end
654
+
655
+ end
656
+
657
+ module Transitional
658
+
659
+ include HTML4
660
+ xx_configure "doctype", %(html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN")
661
+ def html4_ which = HTML4::Transitional, *a, &b
662
+
663
+ super(which, *a, &b)
664
+
665
+ end
666
+
667
+ end
668
+
669
+ end
670
+ HTML = HTML4
671
+
672
+ module XML
673
+
674
+ include Markup
675
+ xx_configure "xmldecl", ::REXML::XMLDecl::new
676
+
677
+ def xml_ *a, &b
678
+
679
+ xx_which(XML){ xx_with_doc_in_effect(*a, &b)}
680
+
681
+ end
682
+
683
+ end
684
+
685
+ end
686
+
687
+ $__xx_rb__ = __FILE__
688
+ end
689
+
690
+
691
+
692
+
693
+
694
+
695
+
696
+
697
+
698
+
699
+ #
700
+ # simple examples - see samples/ dir for more complete examples
701
+ #
702
+
703
+ if __FILE__ == $0
704
+
705
+ class Table < ::Array
706
+ include XX::XHTML::Strict
707
+ include XX::HTML4::Strict
708
+ include XX::XML
709
+
710
+ def doc
711
+ html_{
712
+ head_{ title_{ "xhtml/html4/xml demo" } }
713
+
714
+ div_{
715
+ h_{ "< malformed html & un-escaped symbols" }
716
+ }
717
+
718
+ t_{ "escaped & text > <" }
719
+
720
+ x_{ "<any_valid> xml </any_valid>" }
721
+
722
+ div_(:style => :sweet){
723
+ em_ "this is a table"
724
+
725
+ table_(:width => 42, :height => 42){
726
+ each{|row| tr_{ row.each{|cell| td_ cell } } }
727
+ }
728
+ }
729
+
730
+ script_(:type => :dangerous){ cdata_{ "javascript" } }
731
+ }
732
+ end
733
+ def to_xhtml
734
+ xhtml_{ doc }
735
+ end
736
+ def to_html4
737
+ html4_{ doc }
738
+ end
739
+ def to_xml
740
+ xml_{ doc }
741
+ end
742
+ end
743
+
744
+ table = Table[ %w( 0 1 2 ), %w( a b c ) ]
745
+
746
+ methods = %w( to_xhtml to_html4 to_xml )
747
+
748
+ methods.each do |method|
749
+ 2.times{ puts "-" * 42 }
750
+ puts(table.send(method).pretty)
751
+ puts
752
+ end
753
+
754
+ end