builder 3.0.0 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -11,6 +11,10 @@ module Builder
11
11
  # Builder::XmlMarkup and Builder::XmlEvents for examples.
12
12
  class XmlBase < BlankSlate
13
13
 
14
+ class << self
15
+ attr_accessor :cache_method_calls
16
+ end
17
+
14
18
  # Create an XML markup builder.
15
19
  #
16
20
  # out:: Object receiving the markup. +out+ must respond to
@@ -26,21 +30,15 @@ module Builder
26
30
  @level = initial
27
31
  @encoding = encoding.downcase
28
32
  end
29
-
33
+
30
34
  # Create a tag named +sym+. Other than the first argument which
31
35
  # is the tag name, the arguments are the same as the tags
32
36
  # implemented via <tt>method_missing</tt>.
33
37
  def tag!(sym, *args, &block)
34
- method_missing(sym.to_sym, *args, &block)
35
- end
36
-
37
- # Create XML markup based on the name of the method. This method
38
- # is never invoked directly, but is called for each markup method
39
- # in the markup block.
40
- def method_missing(sym, *args, &block)
41
38
  text = nil
42
39
  attrs = nil
43
40
  sym = "#{sym}:#{args.shift}" if args.first.kind_of?(::Symbol)
41
+ sym = sym.to_sym unless sym.class == ::Symbol
44
42
  args.each do |arg|
45
43
  case arg
46
44
  when ::Hash
@@ -80,6 +78,14 @@ module Builder
80
78
  @target
81
79
  end
82
80
 
81
+ # Create XML markup based on the name of the method. This method
82
+ # is never invoked directly, but is called for each markup method
83
+ # in the markup block that isn't cached.
84
+ def method_missing(sym, *args, &block)
85
+ cache_method_call(sym) if ::Builder::XmlBase.cache_method_calls
86
+ tag!(sym, *args, &block)
87
+ end
88
+
83
89
  # Append text to the output target. Escape any markup. May be
84
90
  # used within the markup brackets as:
85
91
  #
@@ -87,7 +93,7 @@ module Builder
87
93
  def text!(text)
88
94
  _text(_escape(text))
89
95
  end
90
-
96
+
91
97
  # Append text to the output target without escaping any markup.
92
98
  # May be used within the markup brackets as:
93
99
  #
@@ -104,7 +110,7 @@ module Builder
104
110
  def <<(text)
105
111
  _text(text)
106
112
  end
107
-
113
+
108
114
  # For some reason, nil? is sent to the XmlMarkup object. If nil?
109
115
  # is not defined and method_missing is invoked, some strange kind
110
116
  # of recursion happens. Since nil? won't ever be an XML tag, it
@@ -116,7 +122,7 @@ module Builder
116
122
  end
117
123
 
118
124
  private
119
-
125
+
120
126
  require 'builder/xchar'
121
127
  if ::String.method_defined?(:encode)
122
128
  def _escape(text)
@@ -132,29 +138,51 @@ module Builder
132
138
  end
133
139
  else
134
140
  def _escape(text)
135
- text.to_xs((@encoding != 'utf-8' or $KCODE != 'UTF8'))
141
+ if (text.method(:to_xs).arity == 0)
142
+ text.to_xs
143
+ else
144
+ text.to_xs((@encoding != 'utf-8' or $KCODE != 'UTF8'))
145
+ end
136
146
  end
137
147
  end
138
148
 
139
- def _escape_quote(text)
140
- _escape(text).gsub(%r{"}, '&quot;') # " WART
149
+ def _escape_attribute(text)
150
+ _escape(text).gsub("\n", "&#10;").gsub("\r", "&#13;").
151
+ gsub(%r{"}, '&quot;') # " WART
141
152
  end
142
153
 
143
154
  def _newline
144
155
  return if @indent == 0
145
156
  text! "\n"
146
157
  end
147
-
158
+
148
159
  def _indent
149
160
  return if @indent == 0 || @level == 0
150
161
  text!(" " * (@level * @indent))
151
162
  end
152
-
163
+
153
164
  def _nested_structures(block)
154
165
  @level += 1
155
166
  block.call(self)
156
167
  ensure
157
168
  @level -= 1
158
169
  end
170
+
171
+ # If XmlBase.cache_method_calls = true, we dynamicly create the method
172
+ # missed as an instance method on the XMLBase object. Because XML
173
+ # documents are usually very repetative in nature, the next node will
174
+ # be handled by the new method instead of method_missing. As
175
+ # method_missing is very slow, this speeds up document generation
176
+ # significantly.
177
+ def cache_method_call(sym)
178
+ instance_eval <<-NEW_METHOD
179
+ def #{sym.to_s}(*args, &block)
180
+ tag!(:#{sym.to_s}, *args, &block)
181
+ end
182
+ NEW_METHOD
183
+ end
159
184
  end
185
+
186
+ XmlBase.cache_method_calls = true
187
+
160
188
  end
@@ -317,7 +317,7 @@ module Builder
317
317
  when ::Symbol
318
318
  value.to_s
319
319
  else
320
- _escape_quote(value.to_s)
320
+ _escape_attribute(value.to_s)
321
321
  end
322
322
  end
323
323
 
@@ -58,7 +58,7 @@ end
58
58
 
59
59
  # Introduce some late methods (both module and direct) into the Object
60
60
  # class.
61
- class Object
61
+ class Object
62
62
  include LateObject
63
63
  def another_late_addition
64
64
  4321
@@ -82,17 +82,23 @@ end
82
82
  #
83
83
  class TestBlankSlate < Test::Unit::TestCase
84
84
  if Object::const_defined?(:BasicObject)
85
- def self.suite
86
- # skip tests if :BasicObject is present
87
- Test::Unit::TestSuite.new(name)
85
+ def skipping?
86
+ true
87
+ end
88
+ else
89
+ def skipping?
90
+ false
88
91
  end
89
92
  end
90
93
 
91
94
  def setup
95
+ return if skipping?
96
+ @skip = Object::const_defined?(:BasicObject)
92
97
  @bs = BlankSlate.new
93
98
  end
94
99
 
95
100
  def test_undefined_methods_remain_undefined
101
+ return if skipping?
96
102
  assert_raise(NoMethodError) { @bs.no_such_method }
97
103
  assert_raise(NoMethodError) { @bs.nil? }
98
104
  end
@@ -101,6 +107,7 @@ class TestBlankSlate < Test::Unit::TestCase
101
107
  # NOTE: NameError is acceptable because the lack of a '.' means that
102
108
  # Ruby can't tell if it is a method or a local variable.
103
109
  def test_undefined_methods_remain_undefined_during_instance_eval
110
+ return if skipping?
104
111
  assert_raise(NoMethodError, NameError) do
105
112
  @bs.instance_eval do nil? end
106
113
  end
@@ -110,62 +117,73 @@ class TestBlankSlate < Test::Unit::TestCase
110
117
  end
111
118
 
112
119
  def test_private_methods_are_undefined
120
+ return if skipping?
113
121
  assert_raise(NoMethodError) do
114
122
  @bs.puts "HI"
115
123
  end
116
124
  end
117
-
125
+
118
126
  def test_targetted_private_methods_are_undefined_during_instance_eval
127
+ return if skipping?
119
128
  assert_raise(NoMethodError, NameError) do
120
129
  @bs.instance_eval do self.puts "HI" end
121
130
  end
122
131
  end
123
-
132
+
124
133
  def test_untargetted_private_methods_are_defined_during_instance_eval
125
134
  oldstdout = $stdout
135
+ return if skipping?
126
136
  $stdout = StringIO.new
127
- @bs.instance_eval do
137
+ @bs.instance_eval do
128
138
  puts "HI"
129
139
  end
130
140
  ensure
131
141
  $stdout = oldstdout
132
142
  end
133
-
143
+
134
144
  def test_methods_added_late_to_kernel_remain_undefined
145
+ return if skipping?
135
146
  assert_equal 1234, nil.late_addition
136
147
  assert_raise(NoMethodError) { @bs.late_addition }
137
148
  end
138
149
 
139
150
  def test_methods_added_late_to_object_remain_undefined
151
+ return if skipping?
140
152
  assert_equal 4321, nil.another_late_addition
141
153
  assert_raise(NoMethodError) { @bs.another_late_addition }
142
154
  end
143
-
155
+
144
156
  def test_methods_added_late_to_global_remain_undefined
157
+ return if skipping?
145
158
  assert_equal 42, global_inclusion
146
159
  assert_raise(NoMethodError) { @bs.global_inclusion }
147
160
  end
148
161
 
149
162
  def test_preload_method_added
163
+ return if skipping?
150
164
  assert Kernel.k_added_names.include?(:late_addition)
151
165
  assert Object.o_added_names.include?(:another_late_addition)
152
166
  end
153
167
 
154
168
  def test_method_defined_late_multiple_times_remain_undefined
169
+ return if skipping?
155
170
  assert_equal 22, nil.double_late_addition
156
171
  assert_raise(NoMethodError) { @bs.double_late_addition }
157
172
  end
158
173
 
159
174
  def test_late_included_module_in_object_is_ok
175
+ return if skipping?
160
176
  assert_equal 33, 1.late_object
161
177
  assert_raise(NoMethodError) { @bs.late_object }
162
178
  end
163
179
 
164
180
  def test_late_included_module_in_kernel_is_ok
181
+ return if skipping?
165
182
  assert_raise(NoMethodError) { @bs.late_kernel }
166
183
  end
167
184
 
168
185
  def test_revealing_previously_hidden_methods_are_callable
186
+ return if skipping?
169
187
  with_to_s = Class.new(BlankSlate) do
170
188
  reveal :to_s
171
189
  end
@@ -173,12 +191,13 @@ class TestBlankSlate < Test::Unit::TestCase
173
191
  end
174
192
 
175
193
  def test_revealing_previously_hidden_methods_are_callable_with_block
194
+ return if skipping?
176
195
  Object.class_eval <<-EOS
177
196
  def given_block(&block)
178
197
  block
179
- end
198
+ end
180
199
  EOS
181
-
200
+
182
201
  with_given_block = Class.new(BlankSlate) do
183
202
  reveal :given_block
184
203
  end
@@ -186,6 +205,7 @@ class TestBlankSlate < Test::Unit::TestCase
186
205
  end
187
206
 
188
207
  def test_revealing_a_hidden_method_twice_is_ok
208
+ return if skipping?
189
209
  with_to_s = Class.new(BlankSlate) do
190
210
  reveal :to_s
191
211
  reveal :to_s
@@ -194,6 +214,7 @@ class TestBlankSlate < Test::Unit::TestCase
194
214
  end
195
215
 
196
216
  def test_revealing_unknown_hidden_method_is_an_error
217
+ return if skipping?
197
218
  assert_raises(RuntimeError) do
198
219
  Class.new(BlankSlate) do
199
220
  reveal :xyz
@@ -202,6 +223,7 @@ class TestBlankSlate < Test::Unit::TestCase
202
223
  end
203
224
 
204
225
  def test_global_includes_still_work
226
+ return if skipping?
205
227
  assert_nothing_raised do
206
228
  assert_equal 42, global_inclusion
207
229
  assert_equal 42, Object.new.global_inclusion
@@ -211,6 +233,7 @@ class TestBlankSlate < Test::Unit::TestCase
211
233
  end
212
234
 
213
235
  def test_reveal_should_not_bind_to_an_instance
236
+ return if skipping?
214
237
  with_object_id = Class.new(BlankSlate) do
215
238
  reveal(:object_id)
216
239
  end
@@ -218,7 +241,7 @@ class TestBlankSlate < Test::Unit::TestCase
218
241
  obj1 = with_object_id.new
219
242
  obj2 = with_object_id.new
220
243
 
221
- assert obj1.object_id != obj2.object_id,
244
+ assert obj1.object_id != obj2.object_id,
222
245
  "Revealed methods should not be bound to a particular instance"
223
246
  end
224
247
  end
@@ -78,7 +78,13 @@ class TestMarkup < Test::Unit::TestCase
78
78
  @xml.a("link", :href=>"http://onestepback.org")
79
79
  assert_equal %{<a href="http://onestepback.org">link</a>}, @xml.target!
80
80
  end
81
-
81
+
82
+ def test_attributes_with_newlines
83
+ @xml.abbr("W3C", :title=>"World\nWide\rWeb\r\nConsortium")
84
+ assert_equal %{<abbr title="World&#10;Wide&#13;Web&#13;&#10;Consortium">W3C</abbr>},
85
+ @xml.target!
86
+ end
87
+
82
88
  def test_complex
83
89
  @xml.body(:bg=>"#ffffff") { |x|
84
90
  x.title("T", :style=>"red")
@@ -114,9 +120,9 @@ class TestMarkup < Test::Unit::TestCase
114
120
 
115
121
  def test_append_text
116
122
  @xml.p { |x| x.br; x.text! "HI" }
117
- assert_equal "<p><br/>HI</p>", @xml.target!
123
+ assert_equal "<p><br/>HI</p>", @xml.target!
118
124
  end
119
-
125
+
120
126
  def test_ambiguous_markup
121
127
  ex = assert_raise(ArgumentError) {
122
128
  @xml.h1("data1") { b }
@@ -207,7 +213,7 @@ class TestNameSpaces < Test::Unit::TestCase
207
213
  def test_long
208
214
  xml = Builder::XmlMarkup.new(:indent=>2)
209
215
  xml.instruct!
210
- xml.rdf :RDF,
216
+ xml.rdf :RDF,
211
217
  "xmlns:rdf" => :"&rdf;",
212
218
  "xmlns:rdfs" => :"&rdfs;",
213
219
  "xmlns:xsd" => :"&xsd;",
@@ -227,7 +233,7 @@ class TestNameSpaces < Test::Unit::TestCase
227
233
  assert_match /xmlns:rdf="&rdf;"/m, xml.target!
228
234
  assert_match /<owl:Restriction>/m, xml.target!
229
235
  end
230
-
236
+
231
237
  def test_ensure
232
238
  xml = Builder::XmlMarkup.new
233
239
  xml.html do
@@ -446,7 +452,8 @@ class TestIndentedXmlMarkup < Test::Unit::TestCase
446
452
  end
447
453
  end
448
454
 
449
- def test_use_entities_if_kcode_is_utf_but_encoding_is_something_else
455
+ # PENDING: Until we figure out how to gsub on non-UTF-8 text.
456
+ def xtest_use_entities_if_kcode_is_utf_but_encoding_is_something_else
450
457
  xml = Builder::XmlMarkup.new
451
458
  xml.instruct!(:xml, :encoding => 'UTF-16')
452
459
  xml.p(encode("\xE2\x80\x99", 'UTF8'))
@@ -527,7 +534,7 @@ class TestIndentedXmlMarkup < Test::Unit::TestCase
527
534
  def initialize
528
535
  @events = []
529
536
  end
530
-
537
+
531
538
  def start_tag(sym, attrs)
532
539
  @events << [:start, sym, attrs]
533
540
  end
@@ -543,4 +550,3 @@ class TestIndentedXmlMarkup < Test::Unit::TestCase
543
550
  end
544
551
 
545
552
  end
546
-
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #--
4
+ # Portions copyright 2011 by Bart ten Brinke (info@retrosync.com).
5
+ # All rights reserved.
6
+
7
+ # Permission is granted for use, copying, modification, distribution,
8
+ # and distribution of modified versions of this work as long as the
9
+ # above copyright notice is included.
10
+ #++
11
+
12
+ require 'test/unit'
13
+ require 'test/preload'
14
+ require 'builder'
15
+
16
+ class TestMethodCaching < Test::Unit::TestCase
17
+
18
+ # We can directly ask if xml object responds to the cache_me or
19
+ # do_not_cache_me methods because xml is derived from BasicObject
20
+ # (and repond_to? is not defined in BasicObject).
21
+ #
22
+ # Instead we are going to stub out method_missing so that it throws
23
+ # an error, and then make sure that error is either thrown or not
24
+ # thrown as appropriate.
25
+
26
+ def teardown
27
+ super
28
+ Builder::XmlBase.cache_method_calls = true
29
+ end
30
+
31
+ def test_method_call_caching
32
+ xml = Builder::XmlMarkup.new
33
+ xml.cache_me
34
+
35
+ def xml.method_missing(*args)
36
+ ::Kernel.fail StandardError, "SHOULD NOT BE CALLED"
37
+ end
38
+ assert_nothing_raised do
39
+ xml.cache_me
40
+ end
41
+ end
42
+
43
+ def test_method_call_caching_disabled
44
+ Builder::XmlBase.cache_method_calls = false
45
+ xml = Builder::XmlMarkup.new
46
+ xml.do_not_cache_me
47
+
48
+ def xml.method_missing(*args)
49
+ ::Kernel.fail StandardError, "SHOULD BE CALLED"
50
+ end
51
+ assert_raise(StandardError, /SHOULD BE CALLED/) do
52
+ xml.do_not_cache_me
53
+ end
54
+ end
55
+
56
+ end
metadata CHANGED
@@ -1,36 +1,31 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: builder
3
- version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 3
7
- - 0
8
- - 0
9
- version: 3.0.0
3
+ version: !ruby/object:Gem::Version
4
+ version: 3.0.1
5
+ prerelease:
10
6
  platform: ruby
11
- authors:
7
+ authors:
12
8
  - Jim Weirich
13
- autorequire: builder
9
+ autorequire:
14
10
  bindir: bin
15
11
  cert_chain: []
16
-
17
- date: 2010-11-17 00:00:00 -05:00
18
- default_executable:
12
+ date: 2012-09-06 00:00:00.000000000 Z
19
13
  dependencies: []
14
+ description: ! 'Builder provides a number of builder objects that make creating structured
15
+ data
20
16
 
21
- description: |
22
- Builder provides a number of builder objects that make creating structured data
23
17
  simple to do. Currently the following builder objects are supported:
24
-
18
+
19
+
25
20
  * XML Markup
21
+
26
22
  * XML Events
27
23
 
24
+ '
28
25
  email: jim@weirichhouse.org
29
26
  executables: []
30
-
31
27
  extensions: []
32
-
33
- extra_rdoc_files:
28
+ extra_rdoc_files:
34
29
  - CHANGES
35
30
  - Rakefile
36
31
  - README
@@ -39,7 +34,7 @@ extra_rdoc_files:
39
34
  - doc/releases/builder-1.2.4.rdoc
40
35
  - doc/releases/builder-2.0.0.rdoc
41
36
  - doc/releases/builder-2.1.1.rdoc
42
- files:
37
+ files:
43
38
  - lib/blankslate.rb
44
39
  - lib/builder/blankslate.rb
45
40
  - lib/builder/xchar.rb
@@ -53,6 +48,7 @@ files:
53
48
  - test/test_cssbuilder.rb
54
49
  - test/test_eventbuilder.rb
55
50
  - test/test_markupbuilder.rb
51
+ - test/test_method_caching.rb
56
52
  - test/test_namecollision.rb
57
53
  - test/test_xchar.rb
58
54
  - CHANGES
@@ -63,44 +59,40 @@ files:
63
59
  - doc/releases/builder-1.2.4.rdoc
64
60
  - doc/releases/builder-2.0.0.rdoc
65
61
  - doc/releases/builder-2.1.1.rdoc
66
- has_rdoc: true
67
62
  homepage: http://onestepback.org
68
63
  licenses: []
69
-
70
64
  post_install_message:
71
- rdoc_options:
65
+ rdoc_options:
72
66
  - --title
73
67
  - Builder -- Easy XML Building
74
68
  - --main
75
69
  - README.rdoc
76
70
  - --line-numbers
77
- require_paths:
71
+ require_paths:
78
72
  - lib
79
- required_ruby_version: !ruby/object:Gem::Requirement
80
- requirements:
81
- - - ">="
82
- - !ruby/object:Gem::Version
83
- segments:
84
- - 0
85
- version: "0"
86
- required_rubygems_version: !ruby/object:Gem::Requirement
87
- requirements:
88
- - - ">="
89
- - !ruby/object:Gem::Version
90
- segments:
91
- - 0
92
- version: "0"
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ! '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
93
85
  requirements: []
94
-
95
86
  rubyforge_project:
96
- rubygems_version: 1.3.6
87
+ rubygems_version: 1.8.15
97
88
  signing_key:
98
89
  specification_version: 3
99
90
  summary: Builders for MarkUp.
100
- test_files:
91
+ test_files:
101
92
  - test/test_blankslate.rb
102
93
  - test/test_cssbuilder.rb
103
94
  - test/test_eventbuilder.rb
104
95
  - test/test_markupbuilder.rb
96
+ - test/test_method_caching.rb
105
97
  - test/test_namecollision.rb
106
98
  - test/test_xchar.rb