opal-builder 3.2.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a028c1a1758c2583c84327753e1b6b7dc2b38c69
4
+ data.tar.gz: 9e60c365204b02b1a30b33c9d09722e31a22ba4d
5
+ SHA512:
6
+ metadata.gz: 72bcc85b6933e9828c5dcc8a6f3c423566c053bd3221444ac2c72b0668e886de532a4c69f0dc323f1edbf4d95aa59aabad9cd227ac9616778c0ada2a795db5ba
7
+ data.tar.gz: c4053e35e203db78bc011965f034275566afb84d07fdee782beac55b439ae56ba95435ec447622420a71c05badacefd427c64b19afd583cd983436efd3ac69e4
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ Gemfile.lock
2
+ pkg
data/.gitmodules ADDED
@@ -0,0 +1,6 @@
1
+ [submodule "builder"]
2
+ path = builder
3
+ url = https://github.com/jimweirich/builder.git
4
+ [submodule "opal-rspec"]
5
+ path = opal-rspec
6
+ url = https://github.com/wied03/opal-rspec.git
data/.travis.yml ADDED
@@ -0,0 +1,10 @@
1
+ language: ruby
2
+
3
+ rvm:
4
+ - 1.9.3
5
+ - 2.0.0
6
+ - 2.1
7
+
8
+ before_install:
9
+ - git submodule update --init
10
+ - (cd opal-rspec; git submodule update --init)
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+
4
+ # Only run this if we don't have them
5
+ system 'git submodule update --init' unless Dir.glob('builder/**').any?
6
+
7
+ # Remove once we're using an opal-rspec GEM
8
+ system 'git submodule update --init; (cd opal-rspec; git submodule update --init)' unless Dir.glob('opal-rspec/**').any?
9
+
10
+ gem 'opal', git: 'https://github.com/opal/opal.git'
11
+ # Until opal-rspec is updated
12
+ gem 'opal-rspec', path: 'opal-rspec'
13
+
data/README.md ADDED
@@ -0,0 +1,57 @@
1
+ # opal-builder
2
+
3
+ [![Build Status](http://img.shields.io/travis/wied03/opal-builder/master.svg?style=flat)](http://travis-ci.org/wied03/opal-builder)
4
+
5
+ An attempt at making the builder XML gem work with Opal
6
+
7
+ ## Usage
8
+
9
+ Add `opal-builder` to your Gemfile (once this is published to Rubygems, TBD):
10
+
11
+ ```ruby
12
+ gem 'opal-builder'
13
+ ```
14
+
15
+ ### Use in your application
16
+
17
+ ```ruby
18
+ require 'builder'
19
+ ```
20
+
21
+ Limitations:
22
+ * declare! can't be used to create DOCTYPES, etc. right now because Opal treats symbols as strings
23
+ * Character set encoding does not work
24
+
25
+ ## Contributing
26
+
27
+ Install required gems at required versions:
28
+
29
+ $ bundle install
30
+
31
+ A simple rake task should run the example specs in `spec/`:
32
+
33
+ $ bundle exec rake
34
+
35
+ ### Run in the browser
36
+
37
+ Run attached rack app to handle building:
38
+
39
+ $ bundle exec rackup
40
+
41
+ Visit the page in any browser and view the console:
42
+
43
+ $ open http://localhost:9292
44
+
45
+ ## License
46
+
47
+ Authors: Brady Wied
48
+
49
+ Copyright (c) 2015, BSW Technology Consulting LLC
50
+ All rights reserved.
51
+
52
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
53
+
54
+ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
55
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
56
+
57
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require 'bundler'
2
+ Bundler.require
3
+
4
+ Bundler::GemHelper.install_tasks
5
+
6
+ require 'opal/rspec/rake_task'
7
+ Opal::RSpec::RakeTask.new(:default)
@@ -0,0 +1,137 @@
1
+ #!/usr/bin/env ruby
2
+ #--
3
+ # Copyright 2004, 2006 by Jim Weirich (jim@weirichhouse.org).
4
+ # All rights reserved.
5
+
6
+ # Permission is granted for use, copying, modification, distribution,
7
+ # and distribution of modified versions of this work as long as the
8
+ # above copyright notice is included.
9
+ #++
10
+
11
+ class String
12
+ if instance_methods.first.is_a?(Symbol)
13
+ def _blankslate_as_name
14
+ to_sym
15
+ end
16
+ else
17
+ def _blankslate_as_name
18
+ self
19
+ end
20
+ end
21
+ end
22
+
23
+ class Symbol
24
+ if instance_methods.first.is_a?(Symbol)
25
+ def _blankslate_as_name
26
+ self
27
+ end
28
+ else
29
+ def _blankslate_as_name
30
+ to_s
31
+ end
32
+ end
33
+ end
34
+
35
+ ######################################################################
36
+ # BlankSlate provides an abstract base class with no predefined
37
+ # methods (except for <tt>\_\_send__</tt> and <tt>\_\_id__</tt>).
38
+ # BlankSlate is useful as a base class when writing classes that
39
+ # depend upon <tt>method_missing</tt> (e.g. dynamic proxies).
40
+ #
41
+ class BlankSlate
42
+ class << self
43
+
44
+ # Hide the method named +name+ in the BlankSlate class. Don't
45
+ # hide +instance_eval+ or any method beginning with "__".
46
+ def hide(name)
47
+ warn_level = $VERBOSE
48
+ $VERBOSE = nil
49
+ if instance_methods.include?(name._blankslate_as_name) &&
50
+ name !~ /^(__|instance_eval$)/
51
+ @hidden_methods ||= {}
52
+ @hidden_methods[name.to_sym] = instance_method(name)
53
+ undef_method name
54
+ end
55
+ ensure
56
+ $VERBOSE = warn_level
57
+ end
58
+
59
+ def find_hidden_method(name)
60
+ @hidden_methods ||= {}
61
+ @hidden_methods[name] || superclass.find_hidden_method(name)
62
+ end
63
+
64
+ # Redefine a previously hidden method so that it may be called on a blank
65
+ # slate object.
66
+ def reveal(name)
67
+ hidden_method = find_hidden_method(name)
68
+ fail "Don't know how to reveal method '#{name}'" unless hidden_method
69
+ define_method(name, hidden_method)
70
+ end
71
+ end
72
+
73
+ instance_methods.each { |m| hide(m) }
74
+ end
75
+
76
+ ######################################################################
77
+ # Since Ruby is very dynamic, methods added to the ancestors of
78
+ # BlankSlate <em>after BlankSlate is defined</em> will show up in the
79
+ # list of available BlankSlate methods. We handle this by defining a
80
+ # hook in the Object and Kernel classes that will hide any method
81
+ # defined after BlankSlate has been loaded.
82
+ #
83
+ module Kernel
84
+ class << self
85
+ alias_method :blank_slate_method_added, :method_added
86
+
87
+ # Detect method additions to Kernel and remove them in the
88
+ # BlankSlate class.
89
+ def method_added(name)
90
+ result = blank_slate_method_added(name)
91
+ return result if self != Kernel
92
+ BlankSlate.hide(name)
93
+ result
94
+ end
95
+ end
96
+ end
97
+
98
+ ######################################################################
99
+ # Same as above, except in Object.
100
+ #
101
+ class Object
102
+ class << self
103
+ alias_method :blank_slate_method_added, :method_added
104
+
105
+ # Detect method additions to Object and remove them in the
106
+ # BlankSlate class.
107
+ def method_added(name)
108
+ result = blank_slate_method_added(name)
109
+ return result if self != Object
110
+ BlankSlate.hide(name)
111
+ result
112
+ end
113
+
114
+ def find_hidden_method(name)
115
+ nil
116
+ end
117
+ end
118
+ end
119
+
120
+ ######################################################################
121
+ # Also, modules included into Object need to be scanned and have their
122
+ # instance methods removed from blank slate. In theory, modules
123
+ # included into Kernel would have to be removed as well, but a
124
+ # "feature" of Ruby prevents late includes into modules from being
125
+ # exposed in the first place.
126
+ #
127
+ class Module
128
+ alias blankslate_original_append_features append_features
129
+ def append_features(mod)
130
+ result = blankslate_original_append_features(mod)
131
+ return result if mod != Object
132
+ instance_methods.each do |name|
133
+ BlankSlate.hide(name)
134
+ end
135
+ result
136
+ end
137
+ end
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env ruby
2
+ #--
3
+ # Copyright 2004, 2006 by Jim Weirich (jim@weirichhouse.org).
4
+ # All rights reserved.
5
+
6
+ # Permission is granted for use, copying, modification, distribution,
7
+ # and distribution of modified versions of this work as long as the
8
+ # above copyright notice is included.
9
+ #++
10
+
11
+ ######################################################################
12
+ # BlankSlate has been promoted to a top level name and is now
13
+ # available as a standalone gem. We make the name available in the
14
+ # Builder namespace for compatibility.
15
+ #
16
+ module Builder
17
+ if Object::const_defined?(:BasicObject)
18
+ BlankSlate = ::BasicObject
19
+ else
20
+ require 'blankslate'
21
+ BlankSlate = ::BlankSlate
22
+ end
23
+ end
@@ -0,0 +1,8 @@
1
+ module Builder
2
+ VERSION_NUMBERS = [
3
+ VERSION_MAJOR = 3,
4
+ VERSION_MINOR = 2,
5
+ VERSION_BUILD = 2,
6
+ ]
7
+ VERSION = VERSION_NUMBERS.join(".")
8
+ end
@@ -0,0 +1,197 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # The XChar library is provided courtesy of Sam Ruby (See
4
+ # http://intertwingly.net/stories/2005/09/28/xchar.rb)
5
+
6
+ # --------------------------------------------------------------------
7
+
8
+ # If the Builder::XChar module is not currently defined, fail on any
9
+ # name clashes in standard library classes.
10
+
11
+ module Builder
12
+ def self.check_for_name_collision(klass, method_name, defined_constant=nil)
13
+ if klass.method_defined?(method_name.to_s)
14
+ fail RuntimeError,
15
+ "Name Collision: Method '#{method_name}' is already defined in #{klass}"
16
+ end
17
+ end
18
+ end
19
+
20
+ if ! defined?(Builder::XChar) and ! String.method_defined?(:encode)
21
+ Builder.check_for_name_collision(String, "to_xs")
22
+ Builder.check_for_name_collision(Fixnum, "xchr")
23
+ end
24
+
25
+ ######################################################################
26
+ module Builder
27
+
28
+ ####################################################################
29
+ # XML Character converter, from Sam Ruby:
30
+ # (see http://intertwingly.net/stories/2005/09/28/xchar.rb).
31
+ #
32
+ module XChar # :nodoc:
33
+
34
+ # See
35
+ # http://intertwingly.net/stories/2004/04/14/i18n.html#CleaningWindows
36
+ # for details.
37
+ CP1252 = { # :nodoc:
38
+ 128 => 8364, # euro sign
39
+ 130 => 8218, # single low-9 quotation mark
40
+ 131 => 402, # latin small letter f with hook
41
+ 132 => 8222, # double low-9 quotation mark
42
+ 133 => 8230, # horizontal ellipsis
43
+ 134 => 8224, # dagger
44
+ 135 => 8225, # double dagger
45
+ 136 => 710, # modifier letter circumflex accent
46
+ 137 => 8240, # per mille sign
47
+ 138 => 352, # latin capital letter s with caron
48
+ 139 => 8249, # single left-pointing angle quotation mark
49
+ 140 => 338, # latin capital ligature oe
50
+ 142 => 381, # latin capital letter z with caron
51
+ 145 => 8216, # left single quotation mark
52
+ 146 => 8217, # right single quotation mark
53
+ 147 => 8220, # left double quotation mark
54
+ 148 => 8221, # right double quotation mark
55
+ 149 => 8226, # bullet
56
+ 150 => 8211, # en dash
57
+ 151 => 8212, # em dash
58
+ 152 => 732, # small tilde
59
+ 153 => 8482, # trade mark sign
60
+ 154 => 353, # latin small letter s with caron
61
+ 155 => 8250, # single right-pointing angle quotation mark
62
+ 156 => 339, # latin small ligature oe
63
+ 158 => 382, # latin small letter z with caron
64
+ 159 => 376, # latin capital letter y with diaeresis
65
+ }
66
+
67
+ # See http://www.w3.org/TR/REC-xml/#dt-chardata for details.
68
+ PREDEFINED = {
69
+ 38 => '&amp;', # ampersand
70
+ 60 => '&lt;', # left angle bracket
71
+ 62 => '&gt;', # right angle bracket
72
+ }
73
+
74
+ # See http://www.w3.org/TR/REC-xml/#charsets for details.
75
+ VALID = [
76
+ 0x9, 0xA, 0xD,
77
+ (0x20..0xD7FF),
78
+ (0xE000..0xFFFD),
79
+ (0x10000..0x10FFFF)
80
+ ]
81
+
82
+ # http://www.fileformat.info/info/unicode/char/fffd/index.htm
83
+ REPLACEMENT_CHAR =
84
+ if String.method_defined?(:encode)
85
+ "\uFFFD"
86
+ elsif $KCODE == 'UTF8'
87
+ "\xEF\xBF\xBD"
88
+ else
89
+ '*'
90
+ end
91
+ end
92
+
93
+ end
94
+
95
+
96
+ if String.method_defined?(:encode)
97
+ module Builder
98
+ module XChar # :nodoc:
99
+ CP1252_DIFFERENCES, UNICODE_EQUIVALENT = Builder::XChar::CP1252.each.
100
+ inject([[],[]]) {|(domain,range),(key,value)|
101
+ [domain << key,range << value]
102
+ }.map {|seq| seq.pack('U*').force_encoding('utf-8')}
103
+
104
+ XML_PREDEFINED = Regexp.new('[' +
105
+ Builder::XChar::PREDEFINED.keys.pack('U*').force_encoding('utf-8') +
106
+ ']')
107
+
108
+ INVALID_XML_CHAR = Regexp.new('[^'+
109
+ Builder::XChar::VALID.map { |item|
110
+ case item
111
+ when Fixnum
112
+ [item].pack('U').force_encoding('utf-8')
113
+ when Range
114
+ [item.first, '-'.ord, item.last].pack('UUU').force_encoding('utf-8')
115
+ end
116
+ }.join +
117
+ ']')
118
+
119
+ ENCODING_BINARY = Encoding.find('BINARY')
120
+ ENCODING_UTF8 = Encoding.find('UTF-8')
121
+ ENCODING_ISO1 = Encoding.find('ISO-8859-1')
122
+
123
+ # convert a string to valid UTF-8, compensating for a number of
124
+ # common errors.
125
+ def XChar.unicode(string)
126
+ if string.encoding == ENCODING_BINARY
127
+ if string.ascii_only?
128
+ string
129
+ else
130
+ string = string.clone.force_encoding(ENCODING_UTF8)
131
+ if string.valid_encoding?
132
+ string
133
+ else
134
+ string.encode(ENCODING_UTF8, ENCODING_ISO1)
135
+ end
136
+ end
137
+
138
+ elsif string.encoding == ENCODING_UTF8
139
+ if string.valid_encoding?
140
+ string
141
+ else
142
+ string.encode(ENCODING_UTF8, ENCODING_ISO1)
143
+ end
144
+
145
+ else
146
+ string.encode(ENCODING_UTF8)
147
+ end
148
+ end
149
+
150
+ # encode a string per XML rules
151
+ def XChar.encode(string)
152
+ unicode(string).
153
+ tr(CP1252_DIFFERENCES, UNICODE_EQUIVALENT).
154
+ gsub(INVALID_XML_CHAR, REPLACEMENT_CHAR).
155
+ gsub(XML_PREDEFINED) {|c| PREDEFINED[c.ord]}
156
+ end
157
+ end
158
+ end
159
+
160
+ else
161
+
162
+ ######################################################################
163
+ # Enhance the Fixnum class with a XML escaped character conversion.
164
+ #
165
+ class Fixnum
166
+ XChar = Builder::XChar if ! defined?(XChar)
167
+
168
+ # XML escaped version of chr. When <tt>escape</tt> is set to false
169
+ # the CP1252 fix is still applied but utf-8 characters are not
170
+ # converted to character entities.
171
+ def xchr(escape=true)
172
+ n = XChar::CP1252[self] || self
173
+ case n when *XChar::VALID
174
+ XChar::PREDEFINED[n] or
175
+ (n<128 ? n.chr : (escape ? "&##{n};" : [n].pack('U*')))
176
+ else
177
+ Builder::XChar::REPLACEMENT_CHAR
178
+ end
179
+ end
180
+ end
181
+
182
+
183
+ ######################################################################
184
+ # Enhance the String class with a XML escaped character version of
185
+ # to_s.
186
+ #
187
+ class String
188
+ # XML escaped version of to_s. When <tt>escape</tt> is set to false
189
+ # the CP1252 fix is still applied but utf-8 characters are not
190
+ # converted to character entities.
191
+ def to_xs(escape=true)
192
+ unpack('U*').map {|n| n.xchr(escape)}.join # ASCII, UTF-8
193
+ rescue
194
+ unpack('C*').map {|n| n.xchr}.join # ISO-8859-1, WIN-1252
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,199 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'builder/blankslate'
4
+
5
+ module Builder
6
+
7
+ # Generic error for builder
8
+ class IllegalBlockError < RuntimeError; end
9
+
10
+ # XmlBase is a base class for building XML builders. See
11
+ # Builder::XmlMarkup and Builder::XmlEvents for examples.
12
+ class XmlBase < BlankSlate
13
+
14
+ class << self
15
+ attr_accessor :cache_method_calls
16
+ end
17
+
18
+ # Create an XML markup builder.
19
+ #
20
+ # out :: Object receiving the markup. +out+ must respond to
21
+ # <tt><<</tt>.
22
+ # indent :: Number of spaces used for indentation (0 implies no
23
+ # indentation and no line breaks).
24
+ # initial :: Level of initial indentation.
25
+ # encoding :: When <tt>encoding</tt> and $KCODE are set to 'utf-8'
26
+ # characters aren't converted to character entities in
27
+ # the output stream.
28
+ def initialize(indent=0, initial=0, encoding='utf-8')
29
+ @indent = indent
30
+ @level = initial
31
+ @encoding = encoding.downcase
32
+ end
33
+
34
+ def explicit_nil_handling?
35
+ @explicit_nil_handling
36
+ end
37
+
38
+ # Create a tag named +sym+. Other than the first argument which
39
+ # is the tag name, the arguments are the same as the tags
40
+ # implemented via <tt>method_missing</tt>.
41
+ def tag!(sym, *args, &block)
42
+ text = nil
43
+ attrs = nil
44
+ sym = "#{sym}:#{args.shift}" if args.first.kind_of?(::Symbol)
45
+ sym = sym.to_sym unless sym.class == ::Symbol
46
+ args.each do |arg|
47
+ case arg
48
+ when ::Hash
49
+ attrs ||= {}
50
+ attrs.merge!(arg)
51
+ when nil
52
+ attrs ||= {}
53
+ attrs.merge!({:nil => true}) if explicit_nil_handling?
54
+ else
55
+ text ||= ''
56
+ text << arg.to_s
57
+ end
58
+ end
59
+ if block
60
+ unless text.nil?
61
+ ::Kernel::raise ::ArgumentError,
62
+ "XmlMarkup cannot mix a text argument with a block"
63
+ end
64
+ _indent
65
+ _start_tag(sym, attrs)
66
+ _newline
67
+ begin
68
+ _nested_structures(block)
69
+ ensure
70
+ _indent
71
+ _end_tag(sym)
72
+ _newline
73
+ end
74
+ elsif text.nil?
75
+ _indent
76
+ _start_tag(sym, attrs, true)
77
+ _newline
78
+ else
79
+ _indent
80
+ _start_tag(sym, attrs)
81
+ text! text
82
+ _end_tag(sym)
83
+ _newline
84
+ end
85
+ @target
86
+ end
87
+
88
+ # Create XML markup based on the name of the method. This method
89
+ # is never invoked directly, but is called for each markup method
90
+ # in the markup block that isn't cached.
91
+ def method_missing(sym, *args, &block)
92
+ cache_method_call(sym) if ::Builder::XmlBase.cache_method_calls
93
+ tag!(sym, *args, &block)
94
+ end
95
+
96
+ # Append text to the output target. Escape any markup. May be
97
+ # used within the markup brackets as:
98
+ #
99
+ # builder.p { |b| b.br; b.text! "HI" } #=> <p><br/>HI</p>
100
+ def text!(text)
101
+ _text(_escape(text))
102
+ end
103
+
104
+ # Append text to the output target without escaping any markup.
105
+ # May be used within the markup brackets as:
106
+ #
107
+ # builder.p { |x| x << "<br/>HI" } #=> <p><br/>HI</p>
108
+ #
109
+ # This is useful when using non-builder enabled software that
110
+ # generates strings. Just insert the string directly into the
111
+ # builder without changing the inserted markup.
112
+ #
113
+ # It is also useful for stacking builder objects. Builders only
114
+ # use <tt><<</tt> to append to the target, so by supporting this
115
+ # method/operation builders can use other builders as their
116
+ # targets.
117
+ def <<(text)
118
+ _text(text)
119
+ end
120
+
121
+ # For some reason, nil? is sent to the XmlMarkup object. If nil?
122
+ # is not defined and method_missing is invoked, some strange kind
123
+ # of recursion happens. Since nil? won't ever be an XML tag, it
124
+ # is pretty safe to define it here. (Note: this is an example of
125
+ # cargo cult programming,
126
+ # cf. http://fishbowl.pastiche.org/2004/10/13/cargo_cult_programming).
127
+ def nil?
128
+ false
129
+ end
130
+
131
+ private
132
+
133
+ require 'builder/xchar'
134
+ if ::String.method_defined?(:encode)
135
+ def _escape(text)
136
+ result = XChar.encode(text)
137
+ begin
138
+ encoding = ::Encoding::find(@encoding)
139
+ raise Exception if encoding.dummy?
140
+ result.encode(encoding)
141
+ rescue
142
+ # if the encoding can't be supported, use numeric character references
143
+ result.
144
+ gsub(/[^\u0000-\u007F]/) {|c| "&##{c.ord};"}.
145
+ force_encoding('ascii')
146
+ end
147
+ end
148
+ else
149
+ def _escape(text)
150
+ if (text.method(:to_xs).arity == 0)
151
+ text.to_xs
152
+ else
153
+ text.to_xs((@encoding != 'utf-8' or $KCODE != 'UTF8'))
154
+ end
155
+ end
156
+ end
157
+
158
+ def _escape_attribute(text)
159
+ _escape(text).gsub("\n", "&#10;").gsub("\r", "&#13;").
160
+ gsub(%r{"}, '&quot;') # " WART
161
+ end
162
+
163
+ def _newline
164
+ return if @indent == 0
165
+ text! "\n"
166
+ end
167
+
168
+ def _indent
169
+ return if @indent == 0 || @level == 0
170
+ text!(" " * (@level * @indent))
171
+ end
172
+
173
+ def _nested_structures(block)
174
+ @level += 1
175
+ block.call(self)
176
+ ensure
177
+ @level -= 1
178
+ end
179
+
180
+ # If XmlBase.cache_method_calls = true, we dynamicly create the method
181
+ # missed as an instance method on the XMLBase object. Because XML
182
+ # documents are usually very repetative in nature, the next node will
183
+ # be handled by the new method instead of method_missing. As
184
+ # method_missing is very slow, this speeds up document generation
185
+ # significantly.
186
+ def cache_method_call(sym)
187
+ class << self; self; end.class_eval do
188
+ unless method_defined?(sym)
189
+ define_method(sym) do |*args, &block|
190
+ tag!(sym, *args, &block)
191
+ end
192
+ end
193
+ end
194
+ end
195
+ end
196
+
197
+ XmlBase.cache_method_calls = true
198
+
199
+ end