honkster-erector 0.8.1

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.
Files changed (71) hide show
  1. data/README.txt +116 -0
  2. data/VERSION.yml +4 -0
  3. data/bin/erector +14 -0
  4. data/lib/erector.rb +34 -0
  5. data/lib/erector/abstract_widget.rb +172 -0
  6. data/lib/erector/after_initialize.rb +34 -0
  7. data/lib/erector/caching.rb +93 -0
  8. data/lib/erector/convenience.rb +58 -0
  9. data/lib/erector/dependencies.rb +24 -0
  10. data/lib/erector/dependency.rb +30 -0
  11. data/lib/erector/erect/erect.rb +160 -0
  12. data/lib/erector/erect/erected.rb +75 -0
  13. data/lib/erector/erect/indenting.rb +36 -0
  14. data/lib/erector/erect/rhtml.treetop +233 -0
  15. data/lib/erector/errors.rb +12 -0
  16. data/lib/erector/extensions/hash.rb +21 -0
  17. data/lib/erector/extensions/object.rb +18 -0
  18. data/lib/erector/externals.rb +97 -0
  19. data/lib/erector/html.rb +352 -0
  20. data/lib/erector/inline.rb +37 -0
  21. data/lib/erector/jquery.rb +36 -0
  22. data/lib/erector/mixin.rb +12 -0
  23. data/lib/erector/needs.rb +94 -0
  24. data/lib/erector/output.rb +117 -0
  25. data/lib/erector/rails.rb +27 -0
  26. data/lib/erector/rails/extensions/action_controller.rb +16 -0
  27. data/lib/erector/rails/extensions/rails_helpers.rb +159 -0
  28. data/lib/erector/rails/extensions/rails_widget.rb +126 -0
  29. data/lib/erector/rails/rails_form_builder.rb +24 -0
  30. data/lib/erector/rails/rails_version.rb +6 -0
  31. data/lib/erector/rails/template_handlers/ert_handler.rb +32 -0
  32. data/lib/erector/rails/template_handlers/rb_handler.rb +52 -0
  33. data/lib/erector/raw_string.rb +8 -0
  34. data/lib/erector/sass.rb +22 -0
  35. data/lib/erector/unicode.rb +18185 -0
  36. data/lib/erector/unicode_builder.rb +67 -0
  37. data/lib/erector/version.rb +12 -0
  38. data/lib/erector/widget.rb +54 -0
  39. data/lib/erector/widgets.rb +6 -0
  40. data/lib/erector/widgets/environment_badge.rb +29 -0
  41. data/lib/erector/widgets/external_renderer.rb +51 -0
  42. data/lib/erector/widgets/field_table.rb +110 -0
  43. data/lib/erector/widgets/form.rb +30 -0
  44. data/lib/erector/widgets/page.rb +165 -0
  45. data/lib/erector/widgets/table.rb +104 -0
  46. data/rails/init.rb +4 -0
  47. data/spec/erect/erect_rails_spec.rb +114 -0
  48. data/spec/erect/erect_spec.rb +175 -0
  49. data/spec/erect/erected_spec.rb +164 -0
  50. data/spec/erect/rhtml_parser_spec.rb +361 -0
  51. data/spec/erector/caching_spec.rb +269 -0
  52. data/spec/erector/convenience_spec.rb +259 -0
  53. data/spec/erector/dependency_spec.rb +67 -0
  54. data/spec/erector/externals_spec.rb +236 -0
  55. data/spec/erector/html_spec.rb +509 -0
  56. data/spec/erector/indentation_spec.rb +211 -0
  57. data/spec/erector/inline_spec.rb +94 -0
  58. data/spec/erector/jquery_spec.rb +35 -0
  59. data/spec/erector/mixin_spec.rb +65 -0
  60. data/spec/erector/needs_spec.rb +120 -0
  61. data/spec/erector/output_spec.rb +199 -0
  62. data/spec/erector/sample-file.txt +1 -0
  63. data/spec/erector/sass_spec.rb +33 -0
  64. data/spec/erector/unicode_builder_spec.rb +75 -0
  65. data/spec/erector/widget_spec.rb +250 -0
  66. data/spec/erector/widgets/field_table_spec.rb +133 -0
  67. data/spec/erector/widgets/form_spec.rb +31 -0
  68. data/spec/erector/widgets/page_spec.rb +85 -0
  69. data/spec/erector/widgets/table_spec.rb +99 -0
  70. data/spec/spec_helper.rb +95 -0
  71. metadata +191 -0
@@ -0,0 +1,361 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../spec_helper")
2
+
3
+ require "erector/erect/erect"
4
+
5
+ module ParserTestHelper
6
+ def assert_evals_to_self(input)
7
+ assert_evals_to(input, input)
8
+ end
9
+
10
+ def parse(input)
11
+ result = @parser.parse(input)
12
+ if result
13
+ result.set_indent(0) if result.respond_to? :set_indent
14
+ else
15
+ puts @parser.failure_reason
16
+ puts @parser.terminal_failures.join("\n")
17
+ result.should_not be_nil
18
+ end
19
+ result
20
+ end
21
+ end
22
+
23
+ describe RhtmlParser do
24
+ include ParserTestHelper
25
+
26
+ before :each do
27
+ @parser = RhtmlParser.new
28
+ end
29
+
30
+ it "converts text" do
31
+ parse("hello").convert.should == "text 'hello'\n"
32
+ parse("hello maude!").convert.should == "text 'hello maude!'\n"
33
+ parse(" hello ").convert.should == "text 'hello'\n"
34
+ end
35
+
36
+ it "unescapes HTML entities in text" do
37
+ parse("&lt;").convert.should == "text '<'\n"
38
+ parse("5 &gt; 2").convert.should == "text '5 > 2'\n"
39
+ end
40
+
41
+ it "converts self-closing tags" do
42
+ parse("<br/>").convert.should == "br\n"
43
+ parse("<br />").convert.should == "br\n"
44
+ end
45
+
46
+ it "converts open tag" do
47
+ parse("<div>").convert.should == "div do\n"
48
+ parse("<h1>").convert.should == "h1 do\n"
49
+ end
50
+
51
+ it "converts close tag" do
52
+ parse("</div>").convert.should == "end\n"
53
+ parse("</h1>").convert.should == "end\n"
54
+ end
55
+
56
+ it "converts two nested divs" do
57
+ parse("<div><div></div></div>").convert.should ==
58
+ "div do\n" +
59
+ " div do\n" +
60
+ " end\n" +
61
+ "end\n"
62
+ end
63
+
64
+ it "converts two nested divs with whitespace" do
65
+ parse("<div> <div> </div> </div>").convert.should ==
66
+ "div do\n" +
67
+ " div do\n" +
68
+ " end\n" +
69
+ "end\n"
70
+ end
71
+
72
+ it "converts no open, text, and no close tag" do
73
+ parse("hello</div>").convert.should == "text 'hello'\nend\n"
74
+ end
75
+
76
+ it "converts open, text, and no close tag" do
77
+ parse("<div>hello").convert.should == "div do\n text 'hello'\n"
78
+ end
79
+
80
+ it "converts open, text, close" do
81
+ parse("<div>hello</div>").convert.should == "div do\n text 'hello'\nend\n"
82
+ end
83
+
84
+ it "autocloses an img tag" do
85
+ parse("<img src='foo'>").convert.should == "img :src => 'foo'\n"
86
+ end
87
+
88
+ it "converts a scriptlet" do
89
+ parse("<% foo %>").convert.should == "foo\n"
90
+ end
91
+
92
+ it "converts open, text, scriptlet, text, close" do
93
+ parse("<div>hello <% 5.times do %> very <% end %> much</div>").convert.should ==
94
+ "div do\n" +
95
+ " text 'hello'\n" +
96
+ " 5.times do\n" +
97
+ " text 'very'\n" +
98
+ " end\n" +
99
+ " text 'much'\n" +
100
+ "end\n"
101
+ end
102
+
103
+ it "converts open, scriptlet, text, close" do
104
+ parse("<div><% 5.times do %> very <% end %> much</div>").convert.should ==
105
+ "div do\n" +
106
+ " 5.times do\n" +
107
+ " text 'very'\n" +
108
+ " end\n" +
109
+ " text 'much'\n" +
110
+ "end\n"
111
+ end
112
+
113
+ it "converts open, text, scriptlet, close" do
114
+ parse("<div>hello <% 5.times do %> very <% end %></div>").convert.should ==
115
+ "div do\n" +
116
+ " text 'hello'\n" +
117
+ " 5.times do\n" +
118
+ " text 'very'\n" +
119
+ " end\n" +
120
+ "end\n"
121
+ end
122
+
123
+ it "converts printlets into rawtext statements" do
124
+ parse("<%= 1+1 %>").convert.should == "rawtext 1+1\n"
125
+ parse("<%= link_to \"mom\" %>").convert.should == "rawtext link_to(\"mom\")\n"
126
+ end
127
+
128
+ it "converts h-printlets into text statements" do
129
+ parse("<%=h foo %>").convert.should == "text foo\n"
130
+ parse("<%= h \"mom\" %>").convert.should == "text \"mom\"\n"
131
+ end
132
+
133
+ it "allows naked percent signs inside scriptlets" do
134
+ parse("<% x = 10 % 5 %>").convert.should == "x = 10 % 5\n"
135
+ end
136
+
137
+ it "indents" do
138
+ i = Erector::Indenting.new(nil, nil)
139
+ i.line("foo").should == "foo\n"
140
+ i.line_in("bar").should == "bar\n"
141
+ i.line_in("baz").should == " baz\n"
142
+ i.line("baf").should == " baf\n"
143
+ i.line_out("end").should == " end\n"
144
+ i.line_out("end").should == "end\n"
145
+ end
146
+
147
+ it "indents extra when told to" do
148
+ parse("<div>hello</div>").set_indent(2).convert.should ==
149
+ " div do\n" +
150
+ " text 'hello'\n" +
151
+ " end\n"
152
+ end
153
+
154
+ it "indents scriptlets ending with do and end" do
155
+ parse("<% form_for :foo do |x,y| %><% 5.times do %>hello<% end %><% end %>bye").convert.should ==
156
+ "form_for :foo do |x,y|\n" +
157
+ " 5.times do\n" +
158
+ " text 'hello'\n" +
159
+ " end\n" +
160
+ "end\n" +
161
+ "text 'bye'\n"
162
+ end
163
+
164
+ it "converts HTML attributes" do
165
+ parse("<div id='foo'/>").convert.should == "div :id => 'foo'\n"
166
+ parse("<div id='foo' class='bar'/>").convert.should == "div :id => 'foo', :class => 'bar'\n"
167
+ parse("<div id='foo'>bar</div>").convert.should == "div :id => 'foo' do\n text 'bar'\nend\n"
168
+ end
169
+
170
+ it "processes ERb escapes in attributes, and adds parentheses when required" do
171
+ parse("<div id=\"<%= bar %>\" />").convert.should == "div :id => bar\n"
172
+ parse("<div id=\"foo_<%= bar %>_baz\" />").convert.should == "div(:id => ('foo_' + bar + '_baz'))\n"
173
+ end
174
+
175
+ it "escapes single quotes inside attribute values" do
176
+ @parser.root = :attribute
177
+ parse("a=\"don't worry\"").convert.should == ":a => 'don\\'t worry'"
178
+ end
179
+
180
+ it "escapes single quotes inside text strings" do
181
+ parse("isn't she lovely").convert.should == "text 'isn" + "\\" + "'t she lovely'\n"
182
+ end
183
+
184
+ it "allows newlines where whitespace is allowed" do
185
+ parse("<img src='foo' \nalt='bar' />").convert.should == "img :src => 'foo', :alt => 'bar'\n"
186
+ end
187
+
188
+ it "treats tab characters the same as spaces" do
189
+ parse("<div \t />").convert.should == "div\n"
190
+ end
191
+
192
+ it "deals with HTML entities in text" do
193
+ parse("&lt;").convert.should == "text '<'\n"
194
+ end
195
+
196
+ it "deals with a naked less-than or greater-than sign inside text" do
197
+ parse("if x > 2 or x< 5 then").convert.should == "text 'if x > 2 or x< 5 then'\n"
198
+ end
199
+
200
+ it "wraps printlets in parens if necessary, to avoid warning: parenthesize argument(s) for future version" do
201
+ parse("<%= h \"mom\" %>").convert.should == "text \"mom\"\n"
202
+ parse("<%= h hi \"mom\" %>").convert.should == "text hi(\"mom\")\n"
203
+
204
+ parse("<%= \"mom\" %>").convert.should == "rawtext \"mom\"\n"
205
+ parse("<%= \"hi mom\" %>").convert.should == "rawtext \"hi mom\"\n"
206
+ parse("<%= hi \"mom\" %>").convert.should == "rawtext hi(\"mom\")\n"
207
+
208
+ parse("<%= link_to blah %>").convert.should == "rawtext link_to(blah)\n"
209
+ parse("<%= link_to blah blah %>").convert.should == "rawtext link_to(blah blah)\n"
210
+ parse("<%= link_to blah(blah) %>").convert.should == "rawtext link_to(blah(blah))\n"
211
+
212
+ parse("<%= link_to(blah) %>").convert.should == "rawtext link_to(blah)\n"
213
+ end
214
+
215
+ it "won't parenthesize expressions" do
216
+ parse("<%= h foo / bar %>").convert.should == "text foo / bar\n"
217
+ end
218
+
219
+ it "understands a varname" do
220
+ @parser.root = :varname
221
+ parse("head").text_value.should == "head"
222
+ end
223
+
224
+ it "converts yield printlet into a use of @content_for_layout, commented for your edification" do
225
+ parse("<%= yield %>").convert.should == "rawtext @content_for_layout # Note: you must define @content_for_layout elsewhere\n"
226
+ parse("<%= yield :head %>").convert.should == "rawtext @content_for_head # Note: you must define @content_for_head elsewhere\n"
227
+ parse("<%= \"yield\" %>").convert.should == "rawtext \"yield\"\n"
228
+ parse("<%= \"the yield is good\" %>").convert.should == "rawtext \"the yield is good\"\n"
229
+ end
230
+
231
+ it "parses quoted strings" do
232
+ @parser.root = :quoted
233
+ parse("'foo'").value.should == "foo"
234
+ parse("\"foo\"").value.should == "foo"
235
+ end
236
+
237
+ it "quotes empty strings" do
238
+ @parser.root = :quoted
239
+ parse("''").convert.should == "''"
240
+ end
241
+
242
+ it "converts attributes in isolation" do
243
+ @parser.root = :attribute
244
+ parse("a='foo'").convert.should == ":a => 'foo'"
245
+ parse("a=\"foo\"").convert.should == ":a => 'foo'"
246
+ end
247
+
248
+ it "parses a set of attributes" do
249
+ @parser.root = :attributes
250
+ parse("a='foo' b='bar'").convert.should == " :a => 'foo', :b => 'bar'"
251
+ end
252
+
253
+ it "works with namespaced attributes" do
254
+ @parser.root = :attribute
255
+ parse('xml:lang="en"').convert.should == "'xml:lang' => 'en'"
256
+ end
257
+
258
+ it "deals with HTML entities in attribute values" do
259
+ @parser.root = :attribute
260
+ parse("foo='b<r'").convert.should == ":foo => 'b<r'"
261
+ parse("foo='b&lt;r'").convert.should == ":foo => 'b<r'"
262
+ end
263
+
264
+ it "converts DOCTYPEs" do
265
+ html = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
266
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
267
+ parse(html).convert.should == "rawtext '#{html}'\n"
268
+ end
269
+
270
+ ["<!--[if IE]>", "<![endif]-->", "<![if !IE]>", "<![endif]>", "<!--[if IE 5.5000]>", "<!--[if IE 6]>"].each do |html|
271
+ it "converts IE directive '#{html}'" do
272
+ parse(html).convert.should == "rawtext '#{html}'\n"
273
+ end
274
+ end
275
+
276
+ ## More functional-type specs below here
277
+
278
+ it "ignores spaces, tabs and newlines" do
279
+ parse(" <div>\t\n" + "\thello !" + "\n\t</div>").convert.should ==
280
+ "div do\n" +
281
+ " text 'hello !'\n" +
282
+ "end\n"
283
+ end
284
+
285
+ it "parses some scaffolding" do
286
+ parse("<p>
287
+ <b>Name:</b>
288
+ <%=h @foo.name %>
289
+ </p>").convert.should ==
290
+ "p do\n" +
291
+ " b do\n" +
292
+ " text 'Name:'\n" +
293
+ " end\n" +
294
+ " text @foo.name\n" +
295
+ "end\n"
296
+ end
297
+
298
+ it "parses edit.erb.html" do
299
+ parse("<h1>Editing foo</h1>
300
+
301
+ <%= error_messages_for :foo %>
302
+
303
+ <% form_for(@foo) do |f| %>
304
+ <p>
305
+ <b>Name</b><br />
306
+ <%= f.text_field :name %>
307
+ </p>
308
+
309
+ <p>
310
+ <b>Age</b><br />
311
+ <%= f.text_field :age %>
312
+ </p>
313
+
314
+ <p>
315
+ <%= f.submit \"Update\" %>
316
+ </p>
317
+ <% end %>
318
+
319
+ <%= link_to 'Show', @foo %> |
320
+ <%= link_to 'Back', foos_path %>
321
+ ")
322
+ end
323
+
324
+ it "parses show.html.erb" do
325
+ parse("<p>
326
+ <b>Name:</b>
327
+ <%=h @foo.name %>
328
+ </p>
329
+
330
+ <p>
331
+ <b>Age:</b>
332
+ <%=h @foo.age %>
333
+ </p>
334
+
335
+
336
+ <%= link_to 'Edit', edit_foo_path(@foo) %> |
337
+ <%= link_to 'Back', foos_path %>
338
+ ")
339
+ end
340
+
341
+ it "does meta" do
342
+ parse('<meta http-equiv="content-type" content="text/html;charset=UTF-8" />').convert.should ==
343
+ "meta 'http-equiv' => 'content-type', :content => 'text/html;charset=UTF-8'\n"
344
+ end
345
+
346
+ it "parses JayTee's IE and DOCTYPE test file" do
347
+ parse <<-HTML
348
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
349
+ <html xmlns="http://www.w3.org/1999/xhtml">
350
+ <head>
351
+ <!--[if IE]><link href="custom.css" rel="stylesheet" type="text/css" /><![endif]-->
352
+ <!--[if IE]><link href="custom.css" rel="stylesheet" type="text/css" /><![endif]-->
353
+ <script language="javascript" type="text/javascript"> /* <![CDATA[ */
354
+ var myJavascriptCode = 1; /*]]>*/ </script>
355
+ </head>
356
+ <body>
357
+ </body>
358
+ </html>
359
+ HTML
360
+ end
361
+ end
@@ -0,0 +1,269 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../spec_helper")
2
+
3
+ describe Erector::Cache do
4
+ before do
5
+ @cache = Erector::Cache.new
6
+ end
7
+
8
+ class Johnny < Erector::Widget
9
+ end
10
+
11
+ class June < Erector::Widget
12
+ end
13
+
14
+ it 'caches a class with no parameters' do
15
+ @cache[Johnny] = "ring of fire"
16
+ @cache[Johnny].should == "ring of fire"
17
+ end
18
+
19
+ it 'caches two classes with no parameters' do
20
+ @cache[Johnny] = "ring of fire"
21
+ @cache[June] = "wildwood flower"
22
+ @cache[Johnny].should == "ring of fire"
23
+ @cache[June].should == "wildwood flower"
24
+ end
25
+
26
+ it "stores different slots for the same class with different parameters" do
27
+ @cache[Johnny, {:flames => "higher"}] = "ring of fire"
28
+ @cache[Johnny, {:working => "in a coal mine"}] = "my daddy died young"
29
+
30
+ @cache[Johnny, {:flames => "higher"}].should == "ring of fire"
31
+ @cache[Johnny, {:working => "in a coal mine"}].should == "my daddy died young"
32
+ end
33
+
34
+ it "stores different slots for the same class with same parameters and different content methods" do
35
+ @cache[Johnny, {}, :foo] = "ring of fire"
36
+ @cache[Johnny, {}, :bar] = "my daddy died young"
37
+
38
+ @cache[Johnny, {}, :foo].should == "ring of fire"
39
+ @cache[Johnny, {}, :bar].should == "my daddy died young"
40
+ end
41
+
42
+ describe 'after storing a widget with one parameter' do
43
+ before do
44
+ @cache[Johnny, {:flames => "higher"}] = "ring of fire"
45
+ end
46
+
47
+ it 'doesn\'t get it when passed the class alone' do
48
+ @cache[Johnny].should be_nil
49
+ end
50
+
51
+ it 'doesn\'t get it when passed a different class' do
52
+ @cache[June].should be_nil
53
+ end
54
+
55
+ it 'gets it' do
56
+ @cache[Johnny, {:flames => "higher"}].should == "ring of fire"
57
+ end
58
+
59
+ it 'doesn\'t get it when passed a different parameter key' do
60
+ @cache[Johnny, {:working => "coal mine"}].should be_nil
61
+ end
62
+
63
+ it 'doesn\'t get it when passed a different parameter value' do
64
+ @cache[Johnny, {:flames => "lower"}].should be_nil
65
+ end
66
+
67
+ it 'doesn\'t get it when passed an extra parameter key' do
68
+ @cache[Johnny, {:flames => "higher", :working => "coal mine"}].should be_nil
69
+ end
70
+ end
71
+
72
+ describe 'after storing a widget with more than one parameter' do
73
+ before do
74
+ @cache[Johnny, {:flames => "higher", :working => "coal mine"}] = "ring of fire"
75
+ end
76
+
77
+ it "gets it" do
78
+ @cache[Johnny, {:flames => "higher", :working => "coal mine"}].should == "ring of fire"
79
+ end
80
+
81
+ it 'doesn\'t get it when passed the class alone' do
82
+ @cache[Johnny].should be_nil
83
+ end
84
+
85
+ it "doesn't get it when passed a partial parameter set" do
86
+ @cache[Johnny, {:flames => "higher"}].should be_nil
87
+ end
88
+
89
+ it 'doesn\'t get it when passed a different class' do
90
+ @cache[June].should be_nil
91
+ end
92
+
93
+ it 'doesn\'t get it when passed different a parameter value' do
94
+ @cache[Johnny, {:flames => "lower", :working => "coal mine"}].should be_nil
95
+ end
96
+
97
+ it 'doesn\'t get it when passed an extra parameter key' do
98
+ @cache[Johnny, {:flames => "higher", :working => "coal mine", :hear => "train a' comin'"}].should be_nil
99
+ end
100
+ end
101
+
102
+ describe "expires" do
103
+ it 'a class with no parameters' do
104
+ @cache[Johnny] = "ring of fire"
105
+ @cache.delete(Johnny)
106
+ @cache[Johnny].should be_nil
107
+ end
108
+
109
+ it 'all versions of a class' do
110
+ @cache[Johnny] = "i fell in"
111
+ @cache[Johnny, {:flames => "higher"}] = "ring of fire"
112
+ @cache[Johnny, {:working => "in a coal mine"}] = "my daddy died young"
113
+
114
+ @cache.delete_all(Johnny)
115
+
116
+ @cache[Johnny].should be_nil
117
+ @cache[Johnny, {:flames => "higher"}].should be_nil
118
+ @cache[Johnny, {:working => "in a coal mine"}].should be_nil
119
+ end
120
+
121
+ it '...but not other cached values' do
122
+ @cache[Johnny] = "ring of fire"
123
+ @cache[Johnny, {:flames => 'higher'}] = "higher fire"
124
+ @cache[June] = "wildwood flower"
125
+ @cache.delete(Johnny)
126
+ @cache[Johnny].should be_nil
127
+ @cache[Johnny, {:flames => 'higher'}].should == "higher fire"
128
+ @cache[June].should == "wildwood flower"
129
+ end
130
+ end
131
+ end
132
+
133
+ describe Erector::Caching do
134
+ include Erector::Mixin
135
+
136
+ class Cash < Erector::Widget
137
+ needs :name
138
+ cachable
139
+
140
+ def content
141
+ p do
142
+ text @name
143
+ text " Cash"
144
+ end
145
+ end
146
+ end
147
+
148
+ class Family < Erector::Widget
149
+ cacheable
150
+
151
+ def content
152
+ widget Cash, :name => "Johnny"
153
+ widget Cash, :name => "June"
154
+ end
155
+ end
156
+
157
+ class NotCachable < Erector::Widget
158
+ def content
159
+ text "CONTENT"
160
+ end
161
+ end
162
+
163
+ before do
164
+ @cache = Erector::Cache.new
165
+ Erector::Widget.cache = @cache
166
+ end
167
+
168
+ after do
169
+ Erector::Widget.cache = nil
170
+ end
171
+
172
+ it "has a global cache" do
173
+ Erector::Widget.cache.should == @cache
174
+ end
175
+
176
+ it '-- a widget is not cachable by default' do
177
+ Erector::Widget.cachable?.should be_false
178
+ end
179
+
180
+ it '-- a widget is cachable if you say so in the class definition' do
181
+ Cash.cachable?.should be_true
182
+ end
183
+
184
+ it '-- can be declared cachable using the alternate spelling "cacheable"' do
185
+ Family.cachable?.should be_true
186
+ end
187
+
188
+ describe '#to_html' do
189
+
190
+ it "caches a rendered widget" do
191
+ Cash.new(:name => "Johnny").to_html
192
+ @cache[Cash, {:name => "Johnny"}].to_s.should == "<p>Johnny Cash</p>"
193
+ end
194
+
195
+ it "uses the cached value" do
196
+ @cache[Cash, {:name => "Johnny"}] = "CACHED"
197
+ Cash.new(:name => "Johnny").to_html.should == "CACHED"
198
+ end
199
+
200
+ it "doesn't use the cached value for widgets not declared cachable" do
201
+ @cache[NotCachable] = "CACHED"
202
+ NotCachable.new.to_html.should == "CONTENT"
203
+ end
204
+
205
+ it "doesn't cache widgets not declared cachable" do
206
+ NotCachable.new.to_html
207
+ @cache[NotCachable].should be_nil
208
+ end
209
+
210
+ it "doesn't cache widgets initialized with a block (yet)" do
211
+ Cash.new(:name => "June") do
212
+ text "whatever"
213
+ end.to_html
214
+ @cache[Cash, {:name => "June"}].should be_nil
215
+ end
216
+
217
+ it "caches distinct values when using :content_method_name" do
218
+ widget = Class.new(Erector::Widget) do
219
+ cacheable
220
+
221
+ def foo
222
+ text "foo"
223
+ end
224
+
225
+ def bar
226
+ text "bar"
227
+ end
228
+ end
229
+
230
+ widget.new.to_html(:content_method_name => :foo).should == "foo"
231
+ widget.new.to_html(:content_method_name => :bar).should == "bar"
232
+ end
233
+
234
+ it "works when passing an existing output as a parameter to to_html" do
235
+ pending
236
+ end
237
+ end
238
+
239
+ describe '#widget' do
240
+
241
+ it "caches rendered widgets" do
242
+ Family.new.to_html
243
+ @cache[Cash, {:name => "Johnny"}].to_s.should == "<p>Johnny Cash</p>"
244
+ @cache[Cash, {:name => "June"}].to_s.should == "<p>June Cash</p>"
245
+ end
246
+
247
+ it "uses the cached value" do
248
+ @cache[Cash, {:name => "Johnny"}] = "JOHNNY CACHED"
249
+ Family.new.to_html.should == "JOHNNY CACHED<p>June Cash</p>"
250
+ end
251
+
252
+ class WidgetWithBlock < Erector::Widget
253
+ def content
254
+ call_block
255
+ end
256
+ end
257
+
258
+ it "doesn't cache widgets initialized with a block (yet)" do
259
+ erector {
260
+ w = WidgetWithBlock.new do
261
+ text "in block"
262
+ end
263
+ widget w
264
+ }.should == "in block"
265
+ @cache[WidgetWithBlock].should be_nil
266
+ end
267
+
268
+ end
269
+ end