honkster-erector 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
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