erector 0.7.2 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data/README.txt +17 -3
  2. data/VERSION.yml +2 -2
  3. data/bin/erector +1 -1
  4. data/lib/erector.rb +22 -2
  5. data/lib/erector/after_initialize.rb +34 -0
  6. data/lib/erector/caching.rb +93 -0
  7. data/lib/erector/convenience.rb +58 -0
  8. data/lib/erector/dependencies.rb +24 -0
  9. data/lib/erector/dependency.rb +21 -0
  10. data/lib/erector/{erect.rb → erect/erect.rb} +14 -4
  11. data/lib/erector/{erected.rb → erect/erected.rb} +6 -4
  12. data/lib/erector/{indenting.rb → erect/indenting.rb} +0 -0
  13. data/lib/erector/{rhtml.treetop → erect/rhtml.treetop} +51 -11
  14. data/lib/erector/errors.rb +12 -0
  15. data/lib/erector/extensions/hash.rb +21 -0
  16. data/lib/erector/externals.rb +88 -24
  17. data/lib/erector/html.rb +352 -0
  18. data/lib/erector/inline.rb +5 -5
  19. data/lib/erector/jquery.rb +36 -0
  20. data/lib/erector/mixin.rb +3 -5
  21. data/lib/erector/needs.rb +94 -0
  22. data/lib/erector/output.rb +117 -0
  23. data/lib/erector/rails.rb +2 -2
  24. data/lib/erector/rails/extensions/action_controller.rb +5 -3
  25. data/lib/erector/rails/extensions/rails_helpers.rb +159 -0
  26. data/lib/erector/rails/extensions/rails_widget.rb +98 -56
  27. data/lib/erector/rails/rails_form_builder.rb +8 -4
  28. data/lib/erector/rails/rails_version.rb +2 -2
  29. data/lib/erector/rails/template_handlers/ert_handler.rb +1 -1
  30. data/lib/erector/rails/template_handlers/rb_handler.rb +42 -1
  31. data/lib/erector/raw_string.rb +2 -2
  32. data/lib/erector/sass.rb +22 -0
  33. data/lib/erector/widget.rb +100 -653
  34. data/lib/erector/widgets.rb +1 -0
  35. data/lib/erector/widgets/external_renderer.rb +51 -0
  36. data/lib/erector/widgets/page.rb +45 -63
  37. data/lib/erector/widgets/table.rb +9 -1
  38. data/spec/erect/erect_rails_spec.rb +19 -17
  39. data/spec/erect/erect_spec.rb +11 -1
  40. data/spec/erect/erected_spec.rb +76 -5
  41. data/spec/erect/rhtml_parser_spec.rb +11 -1
  42. data/spec/erector/caching_spec.rb +267 -0
  43. data/spec/erector/convenience_spec.rb +258 -0
  44. data/spec/erector/dependency_spec.rb +46 -0
  45. data/spec/erector/externals_spec.rb +233 -0
  46. data/spec/erector/html_spec.rb +508 -0
  47. data/spec/erector/indentation_spec.rb +84 -24
  48. data/spec/erector/inline_spec.rb +19 -8
  49. data/spec/erector/jquery_spec.rb +35 -0
  50. data/spec/erector/mixin_spec.rb +1 -1
  51. data/spec/erector/needs_spec.rb +120 -0
  52. data/spec/erector/output_spec.rb +199 -0
  53. data/spec/erector/sample-file.txt +1 -0
  54. data/spec/erector/sass_spec.rb +33 -0
  55. data/spec/erector/widget_spec.rb +113 -932
  56. data/spec/erector/widgets/field_table_spec.rb +6 -6
  57. data/spec/erector/widgets/form_spec.rb +3 -3
  58. data/spec/erector/widgets/page_spec.rb +52 -6
  59. data/spec/erector/widgets/table_spec.rb +4 -4
  60. data/spec/spec_helper.rb +70 -29
  61. metadata +56 -19
  62. data/lib/erector/rails/extensions/rails_widget/rails_helpers.rb +0 -137
  63. data/spec/core_spec_suite.rb +0 -3
  64. data/spec/erector/external_spec.rb +0 -110
  65. data/spec/rails_spec_suite.rb +0 -3
  66. data/spec/spec.opts +0 -1
  67. data/spec/spec_suite.rb +0 -40
@@ -0,0 +1 @@
1
+ sample file contents, 2 + 2 = #{2 + 2}
@@ -0,0 +1,33 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../spec_helper")
2
+
3
+ if !Object.const_defined?(:Sass)
4
+ puts "Skipping Sass spec... run 'gem install haml' to enable these tests."
5
+ else
6
+ module CacheSpec
7
+ describe Erector::Sass do
8
+ include Erector::Mixin
9
+ it "works" do
10
+ erector {sass SAMPLE_SASS}.should == SAMPLE_CSS
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ SAMPLE_SASS =<<-SASS
17
+ h1
18
+ height: 118px
19
+ margin-top: 1em
20
+
21
+ .tagline
22
+ font-size: 26px
23
+ text-align: right
24
+ SASS
25
+
26
+ SAMPLE_CSS ="""<style>h1 {
27
+ height: 118px;
28
+ margin-top: 1em; }
29
+
30
+ .tagline {
31
+ font-size: 26px;
32
+ text-align: right; }
33
+ </style>"""
@@ -3,163 +3,119 @@ require 'benchmark'
3
3
 
4
4
  module WidgetSpec
5
5
  describe Erector::Widget do
6
- describe ".all_tags" do
7
- it "returns set of full and empty tags" do
8
- Erector::Widget.all_tags.class.should == Array
9
- Erector::Widget.all_tags.should == Erector::Widget.full_tags + Erector::Widget.empty_tags
10
- end
11
- end
6
+ include Erector::Mixin
12
7
 
13
- describe "#to_s" do
14
- class << self
15
- define_method("invokes #content and returns the string representation of the rendered widget") do
16
- it "invokes #content and returns the string representation of the rendered widget" do
17
- widget = Erector.inline do
18
- div "Hello"
19
- end
20
- mock.proxy(widget).content
21
- widget.to_s.should == "<div>Hello</div>"
8
+ describe "#to_html" do
9
+ it "invokes #content and returns the string representation of the rendered widget" do
10
+ Class.new(Erector::Widget) do
11
+ def content
12
+ text "Hello"
22
13
  end
23
- end
14
+ end.new.to_html.should == "Hello"
24
15
  end
25
16
 
26
- context "when passed no arguments" do
27
- send "invokes #content and returns the string representation of the rendered widget"
17
+ it "supports other content methods via :content_method_name" do
18
+ Class.new(Erector::Widget) do
19
+ def alternate
20
+ text "Alternate"
21
+ end
22
+ end.new.to_html(:content_method_name => :alternate).should == "Alternate"
28
23
  end
29
24
 
30
- context "when passed an argument that is #content" do
31
- send "invokes #content and returns the string representation of the rendered widget"
25
+ it "returns an HTML-safe string" do
26
+ Erector::Widget.new.to_html.should be_html_safe
32
27
  end
33
28
 
34
- context "when passed an argument that is not #content" do
35
- attr_reader :widget
36
- before do
37
- @widget = Erector::Widget.new
38
- def widget.alternate_content
39
- div "Hello from Alternate Write"
40
- end
41
- mock.proxy(widget).alternate_content
42
- end
43
-
44
- it "invokes the passed in method name and returns the string representation of the rendered widget" do
45
- widget.to_s(:content_method_name => :alternate_content).should == "<div>Hello from Alternate Write</div>"
46
- end
29
+ it "accepts an existing string as an output buffer" do
30
+ s = "foo"
31
+ Erector.inline { text "bar" }.to_html(:output => s)
32
+ s.should == "foobar"
33
+ end
47
34
 
48
- it "does not invoke #content" do
49
- dont_allow(widget).content
50
- widget.to_s(:content_method_name => :alternate_content)
51
- end
35
+ it "accepts an existing Output as an output buffer" do
36
+ output = Erector::Output.new
37
+ output << "foo"
38
+ Erector.inline { text "bar" }.to_html(:output => output)
39
+ output.to_s.should == "foobar"
52
40
  end
53
41
  end
54
42
 
55
43
  describe "#to_a" do
56
44
  it "returns an array" do
57
- widget = Erector.inline do
58
- div "Hello"
59
- end
60
- widget.to_a.should == ["<div>", "Hello", "</div>"]
61
- end
62
-
63
- # removing this, since oddly, when i run this test solo it works, but when
64
- # i run it as part of a rake suite, i get the opposite result -Alex
65
- # it "runs faster than using a string as the output" do
66
- # widget = Erector.inline do
67
- # 1000.times do |i|
68
- # div "Lorem ipsum dolor sit amet #{i}, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est #{i} laborum."
69
- # end
70
- # end
71
- #
72
- # times = 20
73
- # time_for_to_a = Benchmark.measure { times.times { widget.to_a } }.total
74
- # # puts "to_a: #{time_for_to_a}"
75
- # time_for_string = Benchmark.measure { times.times { widget.to_s(:output => "") } }.total
76
- # # puts "to_s(''): #{time_for_string}"
77
- #
78
- # percent_faster = (((time_for_string - time_for_to_a) / time_for_string)*100)
79
- # # puts ("%.1f%%" % percent_faster)
80
- #
81
- # (time_for_to_a <= time_for_string).should be_true
82
- # end
83
- end
84
-
85
- describe "#instruct" do
86
- it "when passed no arguments; returns an XML declaration with version 1 and utf-8" do
87
- html = Erector.inline do
88
- instruct
89
- # version must precede encoding, per XML 1.0 4th edition (section 2.8)
90
- end.to_s.should == "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
45
+ a = Erector.inline { div "Hello" }.to_a
46
+ a.should be_an(Array)
47
+ a.join.should == "<div>Hello</div>"
91
48
  end
92
49
  end
93
50
 
94
51
  describe '#widget' do
95
- context "basic nesting" do
96
- before do
97
- class Parent < Erector::Widget
98
- def content
99
- text 1
100
- widget Child do
101
- text 2
102
- third
103
- end
104
- end
52
+ class Orphan < Erector::Widget
53
+ def content
54
+ p @name
55
+ end
56
+ end
105
57
 
106
- def third
107
- text 3
108
- end
58
+ it "renders a widget class" do
59
+ erector do
60
+ div do
61
+ widget Orphan, :name => "Annie"
109
62
  end
63
+ end.should == "<div><p>Annie</p></div>"
64
+ end
110
65
 
111
- class Child < Erector::Widget
112
- def content
113
- super
114
- end
66
+ it "renders a widget instance" do
67
+ erector do
68
+ div do
69
+ widget Orphan.new(:name => "Oliver")
115
70
  end
116
- end
117
-
118
- it "renders nested widgets in the correct order" do
119
- Parent.new.to_s.should == '123'
120
- end
71
+ end.should == "<div><p>Oliver</p></div>"
121
72
  end
122
-
123
- end
124
73
 
125
- describe "#widget" do
126
- class Orphan < Erector::Widget
127
- def content
128
- p @name
129
- end
74
+ it "adds the widget to the parent's output widgets" do
75
+ inner = Class.new(Erector::Widget)
76
+ outer = Erector.inline { widget inner }
77
+ outer.to_html
78
+ outer.output.widgets.should include(inner)
130
79
  end
131
-
132
- context "when passed a class" do
133
- it "renders it" do
134
- Erector.inline do
135
- div do
136
- widget Orphan, :name => "Annie"
137
- end
138
- end.to_s.should == "<div><p>Annie</p></div>"
80
+
81
+ it "supports specifying content_method_name" do
82
+ inner = Class.new(Erector::Widget) do
83
+ def foo; text "foo"; end
139
84
  end
85
+ erector do
86
+ widget inner, {}, :content_method_name => :foo
87
+ end.should == "foo"
140
88
  end
141
-
142
- context "when passed an instance" do
143
- it "renders it" do
144
- Erector.inline do
145
- div do
146
- widget Orphan.new(:name => "Oliver")
89
+
90
+ it "renders nested widgets in the correct order" do
91
+ class Parent < Erector::Widget
92
+ def content
93
+ text 1
94
+ widget Erector::Widget do
95
+ text 2
96
+ third
147
97
  end
148
- end.to_s.should == "<div><p>Oliver</p></div>"
98
+ end
99
+
100
+ def third
101
+ text 3
102
+ end
149
103
  end
104
+
105
+ Parent.new.to_html.should == '123'
150
106
  end
151
107
 
152
108
  context "when nested" do
153
- it "renders the tag around the rest of the block" do
154
- parent_widget = Class.new(Erector::Widget) do
109
+ module WhenNested
110
+ class Parent < Erector::Widget
155
111
  def content
156
112
  div :id => "parent_widget" do
157
113
  super
158
114
  end
159
115
  end
160
116
  end
161
-
162
- child_widget = Class.new(Erector::Widget) do
117
+
118
+ class Child < Erector::Widget
163
119
  def content
164
120
  div :id => "child_widget" do
165
121
  super
@@ -167,7 +123,7 @@ module WidgetSpec
167
123
  end
168
124
  end
169
125
 
170
- grandchild = Class.new(Erector::InlineWidget) do
126
+ class Grandchild < Erector::Widget
171
127
  needs :parent_widget, :child_widget
172
128
  def content
173
129
  widget(@parent_widget) do
@@ -177,24 +133,31 @@ module WidgetSpec
177
133
  end
178
134
  end
179
135
  end
136
+ end
180
137
 
181
- grandchild.new(:parent_widget => parent_widget, :child_widget => child_widget).to_s.should == '<div id="parent_widget"><div id="child_widget"><div id="grandchild"></div></div></div>'
182
-
183
- pending "pretty-print indentation is messed up with nesting" do
184
- grandchild.new(:parent_widget => parent_widget, :child_widget => child_widget).to_pretty.should ==
185
- "<div id=\"parent_widget\">\n" +
186
- " <div id=\"child_widget\">\n" +
187
- " <div id=\"grandchild\"></div>\n" +
188
- " </div>\n" +
189
- "</div>"
190
- end
138
+ it "renders the tag around the rest of the block" do
139
+ WhenNested::Grandchild.new(
140
+ :parent_widget => WhenNested::Parent,
141
+ :child_widget => WhenNested::Child
142
+ ).to_html.should == '<div id="parent_widget"><div id="child_widget"><div id="grandchild"></div></div></div>'
143
+ end
191
144
 
145
+ it "renders the tag around the rest of the block with proper indentation" do
146
+ WhenNested::Grandchild.new(
147
+ :parent_widget => WhenNested::Parent,
148
+ :child_widget => WhenNested::Child
149
+ ).to_pretty.should ==
150
+ "<div id=\"parent_widget\">\n" +
151
+ " <div id=\"child_widget\">\n" +
152
+ " <div id=\"grandchild\"></div>\n" +
153
+ " </div>\n" +
154
+ "</div>\n"
192
155
  end
193
-
156
+
194
157
  it "passes a pointer to the child object back into the parent object's block" do
195
158
  child_widget = Erector::Widget.new
196
-
197
- class Parent < Erector::Widget
159
+
160
+ class Parent2 < Erector::Widget
198
161
  needs :child_widget
199
162
  def content
200
163
  div do
@@ -204,14 +167,12 @@ module WidgetSpec
204
167
  end
205
168
  end
206
169
  end
207
-
208
- Parent.new(:child_widget => child_widget).to_s.should == "<div><b>#{child_widget.dom_id}</b></div>"
209
-
170
+
171
+ Parent2.new(:child_widget => child_widget).to_html.should == "<div><b>#{child_widget.dom_id}</b></div>"
210
172
  end
211
-
212
173
  end
213
174
  end
214
-
175
+
215
176
  describe "#call_block" do
216
177
  it "calls the block with a pointer to self" do
217
178
  inside_arg = nil
@@ -227,624 +188,28 @@ module WidgetSpec
227
188
  end
228
189
  end
229
190
 
230
- describe "#element" do
231
- context "when receiving one argument" do
232
- it "returns an empty element" do
233
- Erector.inline do
234
- element('div')
235
- end.to_s.should == "<div></div>"
236
- end
237
- end
238
-
239
- context "with a attribute hash" do
240
- it "returns an empty element with the attributes" do
241
- html = Erector.inline do
242
- element(
243
- 'div',
244
- :class => "foo bar",
245
- :style => "display: none; color: white; float: left;",
246
- :nil_attribute => nil
247
- )
248
- end.to_s
249
- doc = Nokogiri::HTML(html)
250
- div = doc.at('div')
251
- div[:class].should == "foo bar"
252
- div[:style].should == "display: none; color: white; float: left;"
253
- div[:nil_attribute].should be_nil
254
- end
255
- end
256
-
257
- context "with an array of CSS classes" do
258
- it "returns a tag with the classes separated" do
259
- Erector.inline do
260
- element('div', :class => [:foo, :bar])
261
- end.to_s.should == "<div class=\"foo bar\"></div>";
262
- end
263
- end
264
-
265
- context "with an array of CSS classes as strings" do
266
- it "returns a tag with the classes separated" do
267
- Erector.inline do
268
- element('div', :class => ['foo', 'bar'])
269
- end.to_s.should == "<div class=\"foo bar\"></div>";
270
- end
271
- end
272
-
273
- context "with a CSS class which is a string" do
274
- it "just use that as the attribute value" do
275
- Erector.inline do
276
- element('div', :class => "foo bar")
277
- end.to_s.should == "<div class=\"foo bar\"></div>";
278
- end
279
- end
280
-
281
- context "with an empty array of CSS classes" do
282
- it "does not emit a class attribute" do
283
- Erector.inline do
284
- element('div', :class => [])
285
- end.to_s.should == "<div></div>"
286
- end
287
- end
288
-
289
- context "with many attributes" do
290
- it "alphabetize them" do
291
- Erector.inline do
292
- empty_element('foo', :alpha => "", :betty => "5", :aardvark => "tough",
293
- :carol => "", :demon => "", :erector => "", :pi => "3.14", :omicron => "", :zebra => "", :brain => "")
294
- end.to_s.should == "<foo aardvark=\"tough\" alpha=\"\" betty=\"5\" brain=\"\" carol=\"\" demon=\"\" " \
295
- "erector=\"\" omicron=\"\" pi=\"3.14\" zebra=\"\" />";
296
- end
297
- end
298
-
299
- context "with inner tags" do
300
- it "returns nested tags" do
301
- widget = Erector.inline do
302
- element 'div' do
303
- element 'div'
304
- end
305
- end
306
- widget.to_s.should == '<div><div></div></div>'
307
- end
308
- end
309
-
310
- context "with text" do
311
- it "returns element with inner text" do
312
- Erector.inline do
313
- element 'div', 'test text'
314
- end.to_s.should == "<div>test text</div>"
315
- end
316
- end
317
-
318
- context "with object other than hash" do
319
- it "returns element with inner text == object.to_s" do
320
- object = ['a', 'b']
321
- Erector.inline do
322
- element 'div', object
323
- end.to_s.should == "<div>#{object.to_s}</div>"
324
- end
325
- end
326
-
327
- context "with parameters and block" do
328
- it "returns element with inner html and attributes" do
329
- Erector.inline do
330
- element 'div', 'class' => "foobar" do
331
- element 'span', 'style' => 'display: none;'
332
- end
333
- end.to_s.should == '<div class="foobar"><span style="display: none;"></span></div>'
334
- end
335
- end
336
-
337
- context "with content and parameters" do
338
- it "returns element with content as inner html and attributes" do
339
- Erector.inline do
340
- element 'div', 'test text', :style => "display: none;"
341
- end.to_s.should == '<div style="display: none;">test text</div>'
342
- end
343
- end
344
-
345
- context "with more than three arguments" do
346
- it "raises ArgumentError" do
347
- proc do
348
- Erector.inline do
349
- element 'div', 'foobar', {}, 'fourth'
350
- end.to_s
351
- end.should raise_error(ArgumentError)
352
- end
353
- end
354
-
355
- it "renders the proper full tags" do
356
- Erector::Widget.full_tags.each do |tag_name|
357
- expected = "<#{tag_name}></#{tag_name}>"
358
- actual = Erector.inline do
359
- send(tag_name)
360
- end.to_s
361
- begin
362
- actual.should == expected
363
- rescue Spec::Expectations::ExpectationNotMetError => e
364
- puts "Expected #{tag_name} to be a full element. Expected #{expected}, got #{actual}"
365
- raise e
366
- end
367
- end
368
- end
369
-
370
- describe "quoting" do
371
- context "when outputting text" do
372
- it "quotes it" do
373
- Erector.inline do
374
- element 'div', 'test &<>text'
375
- end.to_s.should == "<div>test &amp;&lt;&gt;text</div>"
376
- end
377
- end
378
-
379
- context "when outputting text via text" do
380
- it "quotes it" do
381
- Erector.inline do
382
- element 'div' do
383
- text "test &<>text"
384
- end
385
- end.to_s.should == "<div>test &amp;&lt;&gt;text</div>"
386
- end
387
- end
388
-
389
- context "when outputting attribute value" do
390
- it "quotes it" do
391
- Erector.inline do
392
- element 'a', :href => "foo.cgi?a&b"
393
- end.to_s.should == "<a href=\"foo.cgi?a&amp;b\"></a>"
394
- end
395
- end
396
-
397
- context "with raw text" do
398
- it "does not quote it" do
399
- Erector.inline do
400
- element 'div' do
401
- text raw("<b>bold</b>")
402
- end
403
- end.to_s.should == "<div><b>bold</b></div>"
404
- end
405
- end
406
-
407
- context "with raw text and no block" do
408
- it "does not quote it" do
409
- Erector.inline do
410
- element 'div', raw("<b>bold</b>")
411
- end.to_s.should == "<div><b>bold</b></div>"
412
- end
413
- end
414
-
415
- context "with raw attribute" do
416
- it "does not quote it" do
417
- Erector.inline do
418
- element 'a', :href => raw("foo?x=&nbsp;")
419
- end.to_s.should == "<a href=\"foo?x=&nbsp;\"></a>"
420
- end
421
- end
422
-
423
- context "with quote in attribute" do
424
- it "quotes it" do
425
- Erector.inline do
426
- element 'a', :onload => "alert(\"foo\")"
427
- end.to_s.should == "<a onload=\"alert(&quot;foo&quot;)\"></a>"
428
- end
429
- end
430
- end
431
-
432
- context "with a non-string, non-raw" do
433
- it "calls to_s and quotes" do
434
- Erector.inline do
435
- element 'a' do
436
- text [7, "foo&bar"]
437
- end
438
- end.to_s.should == "<a>7foo&amp;bar</a>"
439
- end
440
- end
441
- end
442
-
443
- describe "#empty_element" do
444
- context "when receiving attributes" do
445
- it "renders an empty element with the attributes" do
446
- Erector.inline do
447
- empty_element 'input', :name => 'foo[bar]'
448
- end.to_s.should == '<input name="foo[bar]" />'
449
- end
450
- end
451
-
452
- context "when not receiving attributes" do
453
- it "renders an empty element without attributes" do
454
- Erector.inline do
455
- empty_element 'br'
456
- end.to_s.should == '<br />'
457
- end
458
- end
459
-
460
- it "renders the proper empty-element tags" do
461
- Erector::Widget.empty_tags.each do |tag_name|
462
- expected = "<#{tag_name} />"
463
- actual = Erector.inline do
464
- send(tag_name)
465
- end.to_s
466
- begin
467
- actual.should == expected
468
- rescue Spec::Expectations::ExpectationNotMetError => e
469
- puts "Expected #{tag_name} to be an empty-element tag. Expected #{expected}, got #{actual}"
470
- raise e
471
- end
472
- end
473
- end
474
- end
475
-
476
- def capturing_output
477
- output = StringIO.new
478
- $stdout = output
479
- yield
480
- output.string
481
- ensure
482
- $stdout = STDOUT
483
- end
484
-
485
- describe "#comment" do
486
- it "emits a single line comment when receiving a string" do
487
- Erector.inline do
488
- comment "foo"
489
- end.to_s.should == "<!--foo-->\n"
490
- end
491
-
492
- it "emits a multiline comment when receiving a block" do
493
- Erector.inline do
494
- comment do
495
- text "Hello"
496
- text " world!"
497
- end
498
- end.to_s.should == "<!--\nHello world!\n-->\n"
499
- end
500
-
501
- it "emits a multiline comment when receiving a string and a block" do
502
- Erector.inline do
503
- comment "Hello" do
504
- text " world!"
505
- end
506
- end.to_s.should == "<!--Hello\n world!\n-->\n"
507
- end
508
-
509
- # see http://www.w3.org/TR/html4/intro/sgmltut.html#h-3.2.4
510
- it "does not HTML-escape character references" do
511
- Erector.inline do
512
- comment "&nbsp;"
513
- end.to_s.should == "<!--&nbsp;-->\n"
514
- end
515
-
516
- # see http://www.w3.org/TR/html4/intro/sgmltut.html#h-3.2.4
517
- # "Authors should avoid putting two or more adjacent hyphens inside comments."
518
- it "warns if there's two hyphens in a row" do
519
- capturing_output do
520
- Erector.inline do
521
- comment "he was -- awesome!"
522
- end.to_s.should == "<!--he was -- awesome!-->\n"
523
- end.should == "Warning: Authors should avoid putting two or more adjacent hyphens inside comments.\n"
524
- end
525
-
526
- it "renders an IE conditional comment with endif when receiving an if IE" do
527
- Erector.inline do
528
- comment "[if IE]" do
529
- text "Hello IE!"
530
- end
531
- end.to_s.should == "<!--[if IE]>\nHello IE!\n<![endif]-->\n"
532
- end
533
-
534
- it "doesn't render an IE conditional comment if there's just some text in brackets" do
535
- Erector.inline do
536
- comment "[puppies are cute]"
537
- end.to_s.should == "<!--[puppies are cute]-->\n"
538
- end
539
-
540
- end
541
-
542
- describe "#nbsp" do
543
- it "turns consecutive spaces into consecutive non-breaking spaces" do
544
- Erector.inline do
545
- text nbsp("a b")
546
- end.to_s.should == "a&#160;&#160;b"
547
- end
548
-
549
- it "works in text context" do
550
- Erector.inline do
551
- element 'a' do
552
- text nbsp("&<> foo")
553
- end
554
- end.to_s.should == "<a>&amp;&lt;&gt;&#160;foo</a>"
555
- end
556
-
557
- it "works in attribute value context" do
558
- Erector.inline do
559
- element 'a', :href => nbsp("&<> foo")
560
- end.to_s.should == "<a href=\"&amp;&lt;&gt;&#160;foo\"></a>"
561
- end
562
-
563
- it "defaults to a single non-breaking space if given no argument" do
564
- Erector.inline do
565
- text nbsp
566
- end.to_s.should == "&#160;"
567
- end
568
-
569
- end
570
-
571
- describe "#character" do
572
- it "renders a character given the codepoint number" do
573
- Erector.inline do
574
- text character(160)
575
- end.to_s.should == "&#xa0;"
576
- end
577
-
578
- it "renders a character given the unicode name" do
579
- Erector.inline do
580
- text character(:right_arrow)
581
- end.to_s.should == "&#x2192;"
582
- end
583
-
584
- it "renders a character above 0xffff" do
585
- Erector.inline do
586
- text character(:old_persian_sign_ka)
587
- end.to_s.should == "&#x103a3;"
588
- end
589
-
590
- it "throws an exception if a name is not recognized" do
591
- lambda {
592
- Erector.inline do
593
- text character(:no_such_character_name)
594
- end.to_s
595
- }.should raise_error("Unrecognized character no_such_character_name")
596
- end
597
-
598
- it "throws an exception if passed something besides a symbol or integer" do
599
- # Perhaps calling to_s would be more ruby-esque, but that seems like it might
600
- # be pretty confusing when this method can already take either a name or number
601
- lambda {
602
- Erector.inline do
603
- text character([])
604
- end.to_s
605
- }.should raise_error("Unrecognized argument to character: ")
606
- end
607
- end
608
-
609
- describe "#join" do
610
-
611
- it "empty array means nothing to join" do
612
- Erector.inline do
613
- join [], Erector::Widget.new { text "x" }
614
- end.to_s.should == ""
615
- end
616
-
617
- it "larger example with two tabs" do
618
- Erector.inline do
619
- tab1 =
620
- Erector.inline do
621
- a "Upload document", :href => "/upload"
622
- end
623
- tab2 =
624
- Erector.inline do
625
- a "Logout", :href => "/logout"
626
- end
627
- join [tab1, tab2],
628
- Erector::Widget.new { text nbsp(" |"); text " " }
629
- end.to_s.should ==
630
- '<a href="/upload">Upload document</a>&#160;| <a href="/logout">Logout</a>'
631
- end
632
-
633
- it "plain string as join separator means pass it to text" do
634
- Erector.inline do
635
- join [
636
- Erector::Widget.new { text "x" },
637
- Erector::Widget.new { text "y" }
638
- ], "<>"
639
- end.to_s.should == "x&lt;&gt;y"
640
- end
641
-
642
- it "plain string as item to join means pass it to text" do
643
- Erector.inline do
644
- join [
645
- "<",
646
- "&"
647
- ], Erector::Widget.new { text " + " }
648
- end.to_s.should == "&lt; + &amp;"
649
- end
650
-
651
- end
652
-
653
- describe '#h' do
654
- before do
655
- @widget = Erector::Widget.new
656
- end
657
-
658
- it "escapes regular strings" do
659
- @widget.h("&").should == "&amp;"
660
- end
661
-
662
- it "does not escape raw strings" do
663
- @widget.h(@widget.raw("&")).should == "&"
664
- end
665
- end
666
-
667
- describe 'escaping' do
668
- plain = 'if (x < y && x > z) alert("don\'t stop");'
669
- escaped = "if (x &lt; y &amp;&amp; x &gt; z) alert(&quot;don't stop&quot;);"
670
-
671
- describe "#text" do
672
- it "does HTML escape its param" do
673
- Erector.inline { text plain }.to_s.should == escaped
674
- end
675
- end
676
- describe "#rawtext" do
677
- it "doesn't HTML escape its param" do
678
- Erector.inline { rawtext plain }.to_s.should == plain
679
- end
680
- end
681
- describe "#text!" do
682
- it "doesn't HTML escape its param" do
683
- Erector.inline { text! plain }.to_s.should == plain
684
- end
685
- end
686
- describe "#element" do
687
- it "does HTML escape its param" do
688
- Erector.inline { element "foo", plain }.to_s.should == "<foo>#{escaped}</foo>"
689
- end
690
- end
691
- describe "#element!" do
692
- it "doesn't HTML escape its param" do
693
- Erector.inline { element! "foo", plain }.to_s.should == "<foo>#{plain}</foo>"
694
- end
695
- end
696
- end
697
-
698
- describe "#javascript" do
699
- context "when receiving a block" do
700
- it "renders the content inside of script text/javascript tags" do
701
- expected = <<-EXPECTED
702
- <script type="text/javascript">
703
- // <![CDATA[
704
- if (x < y && x > z) alert("don't stop");
705
- // ]]>
706
- </script>
707
- EXPECTED
708
- expected.gsub!(/^ /, '')
709
- Erector.inline do
710
- javascript do
711
- rawtext 'if (x < y && x > z) alert("don\'t stop");'
712
- end
713
- end.to_s.should == expected
714
- end
715
- end
716
-
717
- it "renders the raw content inside script tags when given text" do
718
- expected = <<-EXPECTED
719
- <script type="text/javascript">
720
- // <![CDATA[
721
- alert("&<>'hello");
722
- // ]]>
723
- </script>
724
- EXPECTED
725
- expected.gsub!(/^ /, '')
726
- Erector.inline do
727
- javascript('alert("&<>\'hello");')
728
- end.to_s.should == expected
729
- end
730
-
731
- context "when receiving a params hash" do
732
- it "renders a source file" do
733
- html = Erector.inline do
734
- javascript(:src => "/my/js/file.js")
735
- end.to_s
736
- doc = Nokogiri::HTML(html)
737
- doc.at("script")[:src].should == "/my/js/file.js"
738
- end
739
- end
740
-
741
- context "when receiving text and a params hash" do
742
- it "renders a source file" do
743
- html = Erector.inline do
744
- javascript('alert("&<>\'hello");', :src => "/my/js/file.js")
745
- end.to_s
746
- doc = Nokogiri::HTML(html)
747
- script_tag = doc.at('script')
748
- script_tag[:src].should == "/my/js/file.js"
749
- script_tag.inner_html.should include('alert("&<>\'hello");')
750
- end
751
- end
752
-
753
- context "with too many arguments" do
754
- it "raises ArgumentError" do
755
- proc do
756
- Erector.inline do
757
- javascript 'foobar', {}, 'fourth'
758
- end.to_s
759
- end.should raise_error(ArgumentError)
760
- end
761
- end
762
- end
763
-
764
- describe "#css" do
765
- it "makes a link when passed a string" do
766
- Erector.inline do
767
- css "erector.css"
768
- end.to_s.should == "<link href=\"erector.css\" rel=\"stylesheet\" type=\"text/css\" />"
769
- end
770
-
771
- it "accepts a media attribute" do
772
- Erector.inline do
773
- css "print.css", :media => "print"
774
- end.to_s.should == "<link href=\"print.css\" media=\"print\" rel=\"stylesheet\" type=\"text/css\" />"
775
- end
776
- end
777
-
778
- describe "#to_text" do
779
- it "strips tags" do
780
- Erector.inline do
781
- div "foo"
782
- end.to_text.should == "foo"
783
- end
784
-
785
- it "unescapes named entities" do
786
- s = "my \"dog\" has fleas & <ticks>"
787
- Erector.inline do
788
- text s
789
- end.to_text.should == s
790
- end
791
-
792
- it "ignores >s inside attribute strings" do
793
- Erector.inline do
794
- a "foo", :href => "http://example.com/x>y"
795
- end.to_text.should == "foo"
796
- end
797
-
798
- it "doesn't inherit unwanted pretty-printed whitespace (i.e. it turns off prettyprinting)" do
799
- old_default = Erector::Widget.new.prettyprint_default
800
- begin
801
- Erector::Widget.prettyprint_default = true
802
- Erector.inline do
803
- div { div { div "foo" } }
804
- end.to_text.should == "foo"
805
- ensure
806
- Erector::Widget.prettyprint_default = old_default
807
- end
808
- end
809
- end
810
-
811
- describe "#url" do
812
- it "renders an anchor tag with the same href and text" do
813
- Erector.inline do
814
- url "http://example.com"
815
- end.to_s.should == "<a href=\"http://example.com\">http://example.com</a>"
816
- end
817
-
818
- it "accepts extra attributes" do
819
- Erector.inline do
820
- url "http://example.com", :onclick=>"alert('foo')"
821
- end.to_s.should == "<a href=\"http://example.com\" onclick=\"alert('foo')\">http://example.com</a>"
822
- end
823
- end
824
-
825
191
  describe '#capture' do
826
192
  it "should return content rather than write it to the buffer" do
827
- widget = Erector.inline do
193
+ erector do
828
194
  captured = capture do
829
195
  p 'Captured Content'
830
196
  end
831
197
  div do
832
198
  text captured
833
199
  end
834
- end
835
- widget.to_s.should == '<div><p>Captured Content</p></div>'
200
+ end.should == '<div><p>Captured Content</p></div>'
836
201
  end
837
202
 
838
203
  it "returns a RawString" do
839
204
  captured = nil
840
- Erector.inline do
205
+ erector do
841
206
  captured = capture {}
842
- end.to_s.should == ""
843
- captured.should be_a_kind_of Erector::RawString
207
+ end.should == ""
208
+ captured.should be_a_kind_of(Erector::RawString)
844
209
  end
845
210
 
846
211
  it "works with nested captures" do
847
- widget = Erector.inline do
212
+ erector do
848
213
  captured = capture do
849
214
  captured = capture do
850
215
  p 'Nested Capture'
@@ -855,215 +220,31 @@ module WidgetSpec
855
220
  div do
856
221
  text captured
857
222
  end
858
- end
859
- widget.to_s.should == '<div><p>Captured Content</p><p>Nested Capture</p></div>'
860
- end
861
- end
862
-
863
- describe 'nested' do
864
- it "can insert another widget without raw" do
865
- inner = Erector.inline do
866
- p "foo"
867
- end
868
-
869
- outer = Erector.inline do
870
- div inner
871
- end.to_s.should == '<div><p>foo</p></div>'
223
+ end.should == '<div><p>Captured Content</p><p>Nested Capture</p></div>'
872
224
  end
873
225
  end
874
226
 
875
- describe '#write_via' do
876
- class A < Erector::Widget
877
- def content
878
- p "A"
879
- end
880
- end
881
-
882
- it "renders to a widget's doc" do
883
- class B < Erector::Widget
884
- def content
885
- text "B"
886
- A.new.write_via(self)
887
- text "B"
888
- end
889
- end
890
- b = B.new
891
- b.to_s.should == "B<p>A</p>B"
892
- end
893
-
894
- it "passing a widget to text method renders it" do
895
- Erector.inline do
227
+ describe '#text' do
228
+ it "renders a widget" do
229
+ erector do
896
230
  text "B"
897
- text A.new()
231
+ text Erector.inline { p "A" }
898
232
  text "B"
899
- end.to_s.should == "B<p>A</p>B"
233
+ end.should == "B<p>A</p>B"
900
234
  end
901
-
902
235
  end
903
-
904
- describe "assigning instance variables" do
905
- it "attempting to overwrite a reserved instance variable raises error" do
906
- lambda {
907
- Erector::Widget.new(:output => "foo")
908
- }.should raise_error(ArgumentError)
909
- end
910
236
 
237
+ describe "assigning instance variables" do
911
238
  it "handles instance variable names with and without '@' in the beginning" do
912
239
  html = Erector.inline(:foo => "bar", '@baz' => 'quux') do
913
240
  div do
914
241
  p @foo
915
242
  p @baz
916
243
  end
917
- end.to_s
244
+ end.to_html
918
245
  doc = Nokogiri::HTML(html)
919
246
  doc.css("p").map {|p| p.inner_html}.should == ["bar", "quux"]
920
247
  end
921
248
  end
922
-
923
- context "when declaring parameters with the 'needs' macro" do
924
- it "doesn't complain if there aren't any needs declared" do
925
- class Thing1 < Erector::Widget
926
- end
927
- Thing1.new
928
- end
929
-
930
- it "allows you to say that you don't want any parameters" do
931
- class Thing2 < Erector::Widget
932
- needs nil
933
- end
934
- lambda { Thing2.new }.should_not raise_error
935
- lambda { Thing2.new(:foo => 1) }.should raise_error
936
- end
937
-
938
- it "doesn't complain if you pass it a declared parameter" do
939
- class Thing2b < Erector::Widget
940
- needs :foo
941
- end
942
- lambda { Thing2b.new(:foo => 1) }.should_not raise_error
943
- end
944
-
945
- it "complains if you pass it an undeclared parameter" do
946
- class Thing3 < Erector::Widget
947
- needs :foo
948
- end
949
- lambda { Thing3.new(:bar => 1) }.should raise_error
950
- end
951
-
952
- it "allows multiple declared parameters" do
953
- class Thing4 < Erector::Widget
954
- needs :foo, :bar
955
- end
956
- lambda { Thing4.new(:foo => 1, :bar => 2) }.should_not raise_error
957
- end
958
-
959
- it "complains when passing in an extra parameter after declaring many parameters" do
960
- class Thing5 < Erector::Widget
961
- needs :foo, :bar
962
- end
963
- lambda { Thing5.new(:foo => 1, :bar => 2, :baz => 3) }.should raise_error
964
- end
965
-
966
- it "complains when you forget to pass in a needed parameter" do
967
- class Thing6 < Erector::Widget
968
- needs :foo, :bar
969
- end
970
- lambda { Thing6.new(:foo => 1) }.should raise_error
971
- end
972
-
973
- it "doesn't complain if you omit a parameter with a default value" do
974
- class Thing7 < Erector::Widget
975
- needs :foo
976
- needs :bar => 7
977
- needs :baz => 8
978
- end
979
- lambda {
980
- thing = Thing7.new(:foo => 1, :baz => 3)
981
- thing.instance_variable_get(:@bar).should equal(7)
982
- thing.instance_variable_get(:@baz).should equal(3)
983
- }.should_not raise_error
984
- end
985
-
986
- it "allows multiple values on a line, including default values at the end of the line" do
987
- class Thing8 < Erector::Widget
988
- needs :foo, :bar => 7, :baz => 8
989
- end
990
- lambda {
991
- thing = Thing8.new(:foo => 1, :baz => 2)
992
- thing.instance_variable_get(:@foo).should equal(1)
993
- thing.instance_variable_get(:@bar).should equal(7)
994
- thing.instance_variable_get(:@baz).should equal(2)
995
- }.should_not raise_error
996
- end
997
-
998
- it "allows nil to be a default value" do
999
- class Thing9 < Erector::Widget
1000
- needs :foo => nil
1001
- end
1002
- lambda {
1003
- thing = Thing9.new
1004
- thing.instance_variable_get(:@foo).should be_nil
1005
- }.should_not raise_error
1006
- end
1007
-
1008
- it "accumulates needs across the inheritance chain even with modules mixed in" do
1009
- module Something
1010
- end
1011
-
1012
- class Vehicle < Erector::Widget
1013
- needs :wheels
1014
- end
1015
-
1016
- class Car < Vehicle
1017
- include Something
1018
- needs :engine
1019
- end
1020
-
1021
- lambda { Car.new(:engine => 'V-8', :wheels => 4) }.should_not raise_error
1022
- lambda { Car.new(:engine => 'V-8') }.should raise_error
1023
- lambda { Car.new(:wheels => 4) }.should raise_error
1024
- end
1025
-
1026
- it "no longer defines accessors for each of the needed variables" do
1027
- class NeedfulThing < Erector::Widget
1028
- needs :love
1029
- end
1030
- thing = NeedfulThing.new(:love => "all we need")
1031
- lambda {thing.love}.should raise_error(NoMethodError)
1032
- end
1033
-
1034
- it "no longer complains if you attempt to 'need' a variable whose name overlaps with an existing method" do
1035
- class ThingWithOverlap < Erector::Widget
1036
- needs :text
1037
- end
1038
- lambda { ThingWithOverlap.new(:text => "alas") }.should_not raise_error(ArgumentError)
1039
- end
1040
-
1041
- end
1042
-
1043
- describe "#close_tag" do
1044
- it "works when it's all alone, even though it messes with the indent level" do
1045
- Erector.inline { close_tag :foo }.to_s.should == "</foo>"
1046
- Erector.inline { close_tag :foo; close_tag :bar }.to_s.should == "</foo></bar>"
1047
- end
1048
- end
1049
-
1050
- describe "#dom_id" do
1051
- class NiceWidget < Erector::Widget
1052
- def content
1053
- div :id => dom_id
1054
- end
1055
- end
1056
-
1057
- it "makes a unique id based on the widget's class name and object id" do
1058
- widget = NiceWidget.new
1059
- widget.dom_id.should include("#{widget.object_id}")
1060
- widget.dom_id.should include("NiceWidget")
1061
- end
1062
-
1063
- it "can be used as an HTML id" do
1064
- widget = NiceWidget.new
1065
- widget.to_s.should == "<div id=\"#{widget.dom_id}\"></div>"
1066
- end
1067
- end
1068
249
  end
1069
250
  end