erector 0.3.110 → 0.4.191
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/README.txt +1 -1
- data/bin/erect +0 -0
- data/lib/erector.rb +13 -10
- data/lib/erector/doc.rb +138 -0
- data/lib/erector/erected.rb +1 -1
- data/lib/erector/rails.rb +6 -0
- data/lib/erector/rails/extensions/action_controller.rb +17 -0
- data/lib/erector/rails/extensions/action_view.rb +21 -0
- data/lib/erector/{helpers.rb → rails/extensions/widget.rb} +21 -14
- data/lib/erector/rails/supported_rails_versions.rb +11 -0
- data/lib/erector/rails/template_handlers/action_view_template_handler.rb +92 -0
- data/lib/erector/rhtml.treetop +6 -1
- data/lib/erector/unicode.rb +18185 -0
- data/lib/erector/unicode_builder.rb +67 -0
- data/lib/erector/widget.rb +86 -82
- data/spec/core_spec_suite.rb +3 -0
- data/spec/erect/erect_spec.rb +1 -4
- data/spec/erect/erected_spec.rb +1 -4
- data/spec/erect/rhtml_parser_spec.rb +9 -7
- data/spec/erector/doc_spec.rb +55 -0
- data/spec/erector/indentation_spec.rb +127 -0
- data/spec/erector/unicode_builder_spec.rb +75 -0
- data/spec/erector/widget_spec.rb +339 -175
- data/spec/erector/widgets/table_spec.rb +26 -37
- data/spec/rails_spec_suite.rb +3 -0
- data/spec/spec_helper.rb +11 -6
- data/spec/spec_suite.rb +44 -3
- metadata +54 -28
- data/lib/erector/extensions/action_controller.rb +0 -24
- data/lib/erector/extensions/action_view_template_handler.rb +0 -66
- data/lib/erector/html_parts.rb +0 -63
- data/spec/erector/extensions/render_widget_spec.rb +0 -68
- data/spec/erector/extensions/template_handler_spec.rb +0 -29
- data/spec/erector/rails_helpers_spec.rb +0 -149
- data/spec/rails/standard_helpers_spec.rb +0 -102
- data/spec/rails/view_spec.rb +0 -33
- data/spec/view_caching.rb +0 -30
- data/test/rails_root/app/views/template_handler_spec/test_page.rb +0 -8
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Note that this class is only used in building erector itself
|
|
2
|
+
# (and even then, only needs to be run when there is a new
|
|
3
|
+
# UnicodeData.txt file from unicode.org).
|
|
4
|
+
class Erector::UnicodeBuilder
|
|
5
|
+
|
|
6
|
+
def initialize(input, output)
|
|
7
|
+
@input = input
|
|
8
|
+
@output = output
|
|
9
|
+
@first = true
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def generate()
|
|
13
|
+
@output.puts "Erector::CHARACTERS = {"
|
|
14
|
+
process_file
|
|
15
|
+
@output.puts "}"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def process_file()
|
|
19
|
+
while !@input.eof
|
|
20
|
+
line = @input.gets.strip
|
|
21
|
+
if (line == "")
|
|
22
|
+
next;
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
process_line(line)
|
|
26
|
+
end
|
|
27
|
+
if (!@first)
|
|
28
|
+
@output.puts
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def output_line(line)
|
|
33
|
+
if (!@first)
|
|
34
|
+
@output.puts(',')
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
@output.print(line)
|
|
38
|
+
|
|
39
|
+
@first = false
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def process_line(line)
|
|
43
|
+
fields = line.split(';')
|
|
44
|
+
code_point = fields[0]
|
|
45
|
+
name = fields[1]
|
|
46
|
+
alternate_name = fields[10]
|
|
47
|
+
|
|
48
|
+
if /^</.match(name)
|
|
49
|
+
return ""
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
output name, code_point
|
|
53
|
+
if (!alternate_name.nil? && alternate_name != "")
|
|
54
|
+
output alternate_name, code_point
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def output(name, code_point)
|
|
59
|
+
output_line " :#{namify(name)} => 0x#{code_point.downcase}"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def namify(name)
|
|
63
|
+
name.downcase.gsub(/[- ]/, '_')
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
end
|
|
67
|
+
|
data/lib/erector/widget.rb
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
require 'cgi'
|
|
2
|
-
|
|
3
1
|
module Erector
|
|
4
2
|
|
|
5
3
|
# A Widget is the center of the Erector universe.
|
|
@@ -14,11 +12,11 @@ module Erector
|
|
|
14
12
|
# To render a widget from the outside, instantiate it and call its +to_s+ method.
|
|
15
13
|
#
|
|
16
14
|
# To call one widget from another, inside the parent widget's render method, instantiate the child widget and call
|
|
17
|
-
# its +render_to+ method, passing in +self+ (or self.doc if you prefer). This assures that the same
|
|
15
|
+
# its +render_to+ method, passing in +self+ (or self.doc if you prefer). This assures that the same Doc stream
|
|
18
16
|
# is used, which gives better performance than using +capture+ or +to_s+.
|
|
19
17
|
#
|
|
20
18
|
# In this documentation we've tried to keep the distinction clear between methods that *emit* text and those that
|
|
21
|
-
# *return* text. "Emit" means that it writes
|
|
19
|
+
# *return* text. "Emit" means that it writes Doc to the doc stream; "return" means that it returns a string
|
|
22
20
|
# like a normal method and leaves it up to the caller to emit that string if it wants.
|
|
23
21
|
class Widget
|
|
24
22
|
class << self
|
|
@@ -45,23 +43,41 @@ module Erector
|
|
|
45
43
|
]
|
|
46
44
|
end
|
|
47
45
|
|
|
46
|
+
def after_initialize(instance=nil, &blk)
|
|
47
|
+
if blk
|
|
48
|
+
after_initialize_parts << blk
|
|
49
|
+
elsif instance
|
|
50
|
+
if superclass.respond_to?(:after_initialize)
|
|
51
|
+
superclass.after_initialize instance
|
|
52
|
+
end
|
|
53
|
+
after_initialize_parts.each do |part|
|
|
54
|
+
instance.instance_eval &part
|
|
55
|
+
end
|
|
56
|
+
else
|
|
57
|
+
raise ArgumentError, "You must provide either an instance or a block"
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
protected
|
|
62
|
+
def after_initialize_parts
|
|
63
|
+
@after_initialize_parts ||= []
|
|
64
|
+
end
|
|
48
65
|
end
|
|
49
66
|
|
|
50
|
-
include ActionController::UrlWriter
|
|
51
|
-
include Helpers
|
|
52
67
|
attr_reader :helpers
|
|
53
68
|
attr_reader :assigns
|
|
54
69
|
attr_reader :doc
|
|
55
70
|
attr_reader :block
|
|
56
71
|
attr_reader :parent
|
|
57
72
|
|
|
58
|
-
def initialize(helpers=nil, assigns={},
|
|
73
|
+
def initialize(helpers=nil, assigns={}, io = StringIO.new(""), &block)
|
|
59
74
|
@assigns = assigns
|
|
60
75
|
assign_locals(assigns)
|
|
61
76
|
@helpers = helpers
|
|
62
77
|
@parent = block ? eval("self", block.binding) : nil
|
|
63
|
-
@doc =
|
|
78
|
+
@doc = Doc.new(io)
|
|
64
79
|
@block = block
|
|
80
|
+
self.class.after_initialize self
|
|
65
81
|
end
|
|
66
82
|
|
|
67
83
|
#-- methods for other classes to call, left public for ease of testing and documentation
|
|
@@ -75,26 +91,42 @@ module Erector
|
|
|
75
91
|
end
|
|
76
92
|
end
|
|
77
93
|
end
|
|
94
|
+
|
|
95
|
+
# Set whether Erector should add newlines and indentation in to_s.
|
|
96
|
+
# This is an experimental feature and is subject to change
|
|
97
|
+
# (either in terms of how it is enabled, or in terms of
|
|
98
|
+
# what decisions Erector makes about where to add whitespace).
|
|
99
|
+
# This flag should be set prior to any rendering being done
|
|
100
|
+
# (for example, calls to to_s or to_pretty).
|
|
101
|
+
def enable_prettyprint(enable)
|
|
102
|
+
@doc.enable_prettyprint = enable
|
|
103
|
+
self
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Render (like to_s) but adding newlines and indentation.
|
|
107
|
+
def to_pretty
|
|
108
|
+
enable_prettyprint(true).to_s
|
|
109
|
+
end
|
|
78
110
|
|
|
79
|
-
# Entry point for rendering a widget (and all its children). This method creates a new
|
|
80
|
-
# calls this widget's #render method, converts the
|
|
111
|
+
# Entry point for rendering a widget (and all its children). This method creates a new Doc doc stream,
|
|
112
|
+
# calls this widget's #render method, converts the Doc to a string, and returns the string.
|
|
81
113
|
#
|
|
82
114
|
# If it's called again later
|
|
83
115
|
# then it returns the earlier rendered string, which leads to higher performance, but may have confusing
|
|
84
116
|
# effects if some underlying state has changed. In general we recommend you create a new instance of every
|
|
85
117
|
# widget for each render, unless you know what you're doing.
|
|
86
|
-
def to_s(&blk)
|
|
118
|
+
def to_s(render_method_name=:render, &blk)
|
|
87
119
|
# The @__to_s variable is used as a cache.
|
|
88
120
|
# If it's useful we should add a test for it. -ac
|
|
89
121
|
return @__to_s if @__to_s
|
|
90
|
-
|
|
122
|
+
send(render_method_name, &blk)
|
|
91
123
|
@__to_s = @doc.to_s
|
|
92
124
|
end
|
|
93
|
-
|
|
125
|
+
|
|
94
126
|
alias_method :inspect, :to_s
|
|
95
127
|
|
|
96
128
|
# Template method which must be overridden by all widget subclasses. Inside this method you call the magic
|
|
97
|
-
# #element methods which emit HTML and text to the
|
|
129
|
+
# #element methods which emit HTML and text to the Doc stream.
|
|
98
130
|
def render
|
|
99
131
|
if @block
|
|
100
132
|
instance_eval(&@block)
|
|
@@ -102,7 +134,7 @@ module Erector
|
|
|
102
134
|
end
|
|
103
135
|
|
|
104
136
|
# To call one widget from another, inside the parent widget's render method, instantiate the child widget and call
|
|
105
|
-
# its +render_to+ method, passing in +self+ (or self.doc if you prefer). This assures that the same
|
|
137
|
+
# its +render_to+ method, passing in +self+ (or self.doc if you prefer). This assures that the same Doc stream
|
|
106
138
|
# is used, which gives better performance than using +capture+ or +to_s+.
|
|
107
139
|
def render_to(doc_or_widget)
|
|
108
140
|
if doc_or_widget.is_a?(Widget)
|
|
@@ -114,9 +146,12 @@ module Erector
|
|
|
114
146
|
render
|
|
115
147
|
end
|
|
116
148
|
|
|
117
|
-
# Convenience method for on-the-fly widgets.
|
|
149
|
+
# Convenience method for on-the-fly widgets. This is a way of making
|
|
150
|
+
# a sub-widget which still has access to the methods of the parent class.
|
|
151
|
+
# This is an experimental erector feature which may disappear in future
|
|
152
|
+
# versions of erector (see #widget in widget_spec in the Erector tests).
|
|
118
153
|
def widget(widget_class, assigns={}, &block)
|
|
119
|
-
child = widget_class.new(helpers, assigns, doc, &block)
|
|
154
|
+
child = widget_class.new(helpers, assigns, doc.output, &block)
|
|
120
155
|
child.render
|
|
121
156
|
end
|
|
122
157
|
|
|
@@ -139,7 +174,7 @@ module Erector
|
|
|
139
174
|
# When calling one of these magic methods, put attributes in the default hash. If there is a string parameter,
|
|
140
175
|
# then it is used as the contents. If there is a block, then it is executed (yielded), and the string parameter is ignored.
|
|
141
176
|
# The block will usually be in the scope of the child widget, which means it has access to all the
|
|
142
|
-
# methods of Widget, which will eventually end up appending text to the +doc+
|
|
177
|
+
# methods of Widget, which will eventually end up appending text to the +doc+ Doc stream. See how
|
|
143
178
|
# elegant it is? Not confusing at all if you don't think about it.
|
|
144
179
|
#
|
|
145
180
|
def element(*args, &block)
|
|
@@ -158,7 +193,7 @@ module Erector
|
|
|
158
193
|
__empty_element__(*args, &block)
|
|
159
194
|
end
|
|
160
195
|
|
|
161
|
-
# Returns an HTML-escaped version of its parameter. Leaves the
|
|
196
|
+
# Returns an HTML-escaped version of its parameter. Leaves the Doc stream untouched. Note that
|
|
162
197
|
# the #text method automatically HTML-escapes its parameter, so be careful *not* to do something like
|
|
163
198
|
# text(h("2<4")) since that will double-escape the less-than sign (you'll get "2&lt;4" instead of
|
|
164
199
|
# "2<4").
|
|
@@ -168,13 +203,16 @@ module Erector
|
|
|
168
203
|
|
|
169
204
|
# Emits an open tag, comprising '<', tag name, optional attributes, and '>'
|
|
170
205
|
def open_tag(tag_name, attributes={})
|
|
171
|
-
@doc
|
|
206
|
+
@doc.open_tag tag_name, attributes
|
|
172
207
|
end
|
|
173
208
|
|
|
174
|
-
# Emits text
|
|
209
|
+
# Emits text. If a string is passed in, it will be HTML-escaped.
|
|
210
|
+
# If a widget or the result of calling methods such as raw
|
|
211
|
+
# is passed in, the HTML will not be HTML-escaped again.
|
|
212
|
+
# If another kind of object is passed in, the result of calling
|
|
213
|
+
# its to_s method will be treated as a string would be.
|
|
175
214
|
def text(value)
|
|
176
|
-
@doc
|
|
177
|
-
nil
|
|
215
|
+
@doc.text value
|
|
178
216
|
end
|
|
179
217
|
|
|
180
218
|
# Returns text which will *not* be HTML-escaped.
|
|
@@ -182,32 +220,46 @@ module Erector
|
|
|
182
220
|
RawString.new(value.to_s)
|
|
183
221
|
end
|
|
184
222
|
|
|
185
|
-
#
|
|
223
|
+
# Emits text which will *not* be HTML-escaped. Same effect as text(raw(s))
|
|
186
224
|
def rawtext(value)
|
|
187
225
|
text raw(value)
|
|
188
226
|
end
|
|
189
227
|
|
|
190
228
|
# Returns a copy of value with spaces replaced by non-breaking space characters.
|
|
191
|
-
#
|
|
229
|
+
# With no arguments, return a single non-breaking space.
|
|
230
|
+
# The output uses the escaping format ' ' since that works
|
|
192
231
|
# in both HTML and XML (as opposed to ' ' which only works in HTML).
|
|
193
|
-
def nbsp(value)
|
|
232
|
+
def nbsp(value = " ")
|
|
194
233
|
raw(value.html_escape.gsub(/ /,' '))
|
|
195
234
|
end
|
|
235
|
+
|
|
236
|
+
# Return a character given its unicode code point or unicode name.
|
|
237
|
+
def character(code_point_or_name)
|
|
238
|
+
if code_point_or_name.is_a?(Symbol)
|
|
239
|
+
found = Erector::CHARACTERS[code_point_or_name]
|
|
240
|
+
if found.nil?
|
|
241
|
+
raise "Unrecognized character #{code_point_or_name}"
|
|
242
|
+
end
|
|
243
|
+
raw("&#x#{sprintf '%x', found};")
|
|
244
|
+
elsif code_point_or_name.is_a?(Integer)
|
|
245
|
+
raw("&#x#{sprintf '%x', code_point_or_name};")
|
|
246
|
+
else
|
|
247
|
+
raise "Unrecognized argument to character: #{code_point_or_name}"
|
|
248
|
+
end
|
|
249
|
+
end
|
|
196
250
|
|
|
197
251
|
# Emits a close tag, consisting of '<', tag name, and '>'
|
|
198
252
|
def close_tag(tag_name)
|
|
199
|
-
@doc
|
|
253
|
+
@doc.close_tag tag_name
|
|
200
254
|
end
|
|
201
255
|
|
|
202
256
|
# Emits an XML instruction, which looks like this: <?xml version=\"1.0\" encoding=\"UTF-8\"?>
|
|
203
257
|
def instruct(attributes={:version => "1.0", :encoding => "UTF-8"})
|
|
204
|
-
@doc
|
|
258
|
+
@doc.instruct attributes
|
|
205
259
|
end
|
|
206
260
|
|
|
207
261
|
# Deprecated synonym of instruct
|
|
208
|
-
|
|
209
|
-
@doc << {:type => :instruct, :attributes => attributes}
|
|
210
|
-
end
|
|
262
|
+
alias_method :instruct!, :instruct
|
|
211
263
|
|
|
212
264
|
# Creates a whole new doc stream, executes the block, then converts the doc stream to a string and
|
|
213
265
|
# emits it as raw text. If at all possible you should avoid this method since it hurts performance,
|
|
@@ -215,7 +267,7 @@ module Erector
|
|
|
215
267
|
def capture(&block)
|
|
216
268
|
begin
|
|
217
269
|
original_doc = @doc
|
|
218
|
-
@doc =
|
|
270
|
+
@doc = Doc.new(StringIO.new)
|
|
219
271
|
yield
|
|
220
272
|
raw(@doc.to_s)
|
|
221
273
|
ensure
|
|
@@ -299,6 +351,7 @@ module Erector
|
|
|
299
351
|
|
|
300
352
|
protected
|
|
301
353
|
|
|
354
|
+
# This is part of the sub-widget/parent feature (see #widget method).
|
|
302
355
|
def method_missing(name, *args, &block)
|
|
303
356
|
block ||= lambda {} # captures self HERE
|
|
304
357
|
if @parent
|
|
@@ -308,55 +361,6 @@ protected
|
|
|
308
361
|
end
|
|
309
362
|
end
|
|
310
363
|
|
|
311
|
-
def fake_erbout(&blk)
|
|
312
|
-
# override concat on the helpers object (which is usually a Rails view object)
|
|
313
|
-
unless @helpers.respond_to?(:concat_without_erector)
|
|
314
|
-
@helpers.metaclass.class_eval do
|
|
315
|
-
alias_method :capture_without_erector, :capture
|
|
316
|
-
def capture(*args, &block)
|
|
317
|
-
result = nil
|
|
318
|
-
widget = @erector_widget_stack.first
|
|
319
|
-
begin
|
|
320
|
-
original_doc = widget.doc
|
|
321
|
-
widget.instance_eval do
|
|
322
|
-
@doc = HtmlParts.new
|
|
323
|
-
end
|
|
324
|
-
captured = capture_without_erector(*args, &block)
|
|
325
|
-
result = widget.raw(widget.doc.to_s)
|
|
326
|
-
ensure
|
|
327
|
-
widget.instance_eval do
|
|
328
|
-
@doc = original_doc
|
|
329
|
-
end
|
|
330
|
-
end
|
|
331
|
-
result
|
|
332
|
-
end
|
|
333
|
-
|
|
334
|
-
alias_method :concat_without_erector, :concat
|
|
335
|
-
define_method :concat do |*args|
|
|
336
|
-
some_text, binding = args
|
|
337
|
-
raise "widget stack too big" if @erector_widget_stack.size > 10
|
|
338
|
-
if @erector_widget_stack.empty?
|
|
339
|
-
concat_without_erector(some_text, binding)
|
|
340
|
-
else
|
|
341
|
-
@erector_widget_stack.first.rawtext(some_text)
|
|
342
|
-
end
|
|
343
|
-
end
|
|
344
|
-
define_method :erector_widget_stack do
|
|
345
|
-
@erector_widget_stack ||= []
|
|
346
|
-
end
|
|
347
|
-
end
|
|
348
|
-
end
|
|
349
|
-
|
|
350
|
-
@helpers.erector_widget_stack.unshift(self)
|
|
351
|
-
yield
|
|
352
|
-
ensure
|
|
353
|
-
if @helpers.respond_to?(:concat_without_erector)
|
|
354
|
-
@helpers.erector_widget_stack.shift
|
|
355
|
-
end
|
|
356
|
-
end
|
|
357
|
-
|
|
358
|
-
private
|
|
359
|
-
|
|
360
364
|
def __element__(tag_name, *args, &block)
|
|
361
365
|
if args.length > 2
|
|
362
366
|
raise ArgumentError, "Cannot accept more than three arguments"
|
|
@@ -383,7 +387,7 @@ private
|
|
|
383
387
|
end
|
|
384
388
|
|
|
385
389
|
def __empty_element__(tag_name, attributes={})
|
|
386
|
-
@doc
|
|
390
|
+
@doc.empty_element tag_name, attributes
|
|
387
391
|
end
|
|
388
392
|
|
|
389
393
|
end
|
data/spec/erect/erect_spec.rb
CHANGED
data/spec/erect/erected_spec.rb
CHANGED
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
require "#{dir}/../spec_helper"
|
|
3
|
-
|
|
4
|
-
# require 'test/unit'
|
|
5
|
-
require 'rubygems'
|
|
6
|
-
require 'treetop'
|
|
7
|
-
require "erector/erected" # pull this out so we don't recreate the grammar every time
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../spec_helper")
|
|
8
2
|
|
|
9
3
|
module ParserTestHelper
|
|
10
4
|
def assert_evals_to_self(input)
|
|
@@ -189,6 +183,7 @@ describe RhtmlParser do
|
|
|
189
183
|
parse("<%= h hi \"mom\" %>").convert.should == "text hi(\"mom\")\n"
|
|
190
184
|
|
|
191
185
|
parse("<%= \"mom\" %>").convert.should == "rawtext \"mom\"\n"
|
|
186
|
+
parse("<%= \"hi mom\" %>").convert.should == "rawtext \"hi mom\"\n"
|
|
192
187
|
parse("<%= hi \"mom\" %>").convert.should == "rawtext hi(\"mom\")\n"
|
|
193
188
|
|
|
194
189
|
parse("<%= link_to blah %>").convert.should == "rawtext link_to(blah)\n"
|
|
@@ -202,6 +197,13 @@ describe RhtmlParser do
|
|
|
202
197
|
parse("<%= h foo / bar %>").convert.should == "text foo / bar\n"
|
|
203
198
|
end
|
|
204
199
|
|
|
200
|
+
it "converts yield so layouts work" do
|
|
201
|
+
pending("easy enough to make this pass, but the result doesn't seem to work as a layout")
|
|
202
|
+
parse("<%= yield %>").convert.should == "rawtext @content\n"
|
|
203
|
+
parse("<%= \"yield\" %>").convert.should == "rawtext \"yield\"\n"
|
|
204
|
+
parse("<%= \"the yield is good\" %>").convert.should == "rawtext \"the yield is good\"\n"
|
|
205
|
+
end
|
|
206
|
+
|
|
205
207
|
it "parses quoted strings" do
|
|
206
208
|
@parser.root = :quoted
|
|
207
209
|
parse("'foo'").value.should == "foo"
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../spec_helper")
|
|
2
|
+
|
|
3
|
+
module Erector
|
|
4
|
+
describe Doc do
|
|
5
|
+
describe "#output" do
|
|
6
|
+
it "seeks to the end of the buffer" do
|
|
7
|
+
string = "Hello"
|
|
8
|
+
io = StringIO.new(string)
|
|
9
|
+
doc = Doc.new(io)
|
|
10
|
+
|
|
11
|
+
string.concat(" World")
|
|
12
|
+
doc.text " Again"
|
|
13
|
+
|
|
14
|
+
string.should == "Hello World Again"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe "#method_missing" do
|
|
19
|
+
context "when passed in io object raises a NoMethodError" do
|
|
20
|
+
context "when the passed in io object respond_to? method is false" do
|
|
21
|
+
attr_reader :io
|
|
22
|
+
before do
|
|
23
|
+
@io = StringIO.new
|
|
24
|
+
io.should_not respond_to(:foo)
|
|
25
|
+
lambda {io.foo}.should raise_error(NoMethodError, /undefined method `foo' for #<StringIO/)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "raises a NoMethodError that originates from within Doc#method_missing" do
|
|
29
|
+
doc = Doc.new(io)
|
|
30
|
+
lambda do
|
|
31
|
+
doc.foo
|
|
32
|
+
end.should raise_error(NoMethodError, /undefined method `foo' for #<Erector::Doc/)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
context "when the passed in io object respond_to? method is true" do
|
|
37
|
+
attr_reader :io
|
|
38
|
+
before do
|
|
39
|
+
@io = StringIO.new
|
|
40
|
+
stub(io).foo {raise NoMethodError, "Stubbed NoMethodError"}
|
|
41
|
+
io.should respond_to(:foo)
|
|
42
|
+
lambda {io.foo}.should raise_error(NoMethodError, "Stubbed NoMethodError")
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "raises a NoMethodError that originates from within Doc#method_missing" do
|
|
46
|
+
doc = Doc.new(io)
|
|
47
|
+
lambda do
|
|
48
|
+
doc.foo
|
|
49
|
+
end.should raise_error(NoMethodError, /undefined method `foo' for #<Erector::Doc/)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|