erector-rails4 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (115) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +2 -0
  3. data/.gitignore +10 -0
  4. data/.rspec +1 -0
  5. data/.ruby-gemset +1 -0
  6. data/.ruby-version +1 -0
  7. data/.travis.yml +5 -0
  8. data/Gemfile +6 -0
  9. data/Gemfile.lock +143 -0
  10. data/README.md +4 -0
  11. data/Rakefile +24 -0
  12. data/erector-rails4.gemspec +36 -0
  13. data/erector-rails4.sublimeproject +20 -0
  14. data/lib/erector/abstract_widget.rb +231 -0
  15. data/lib/erector/after_initialize.rb +29 -0
  16. data/lib/erector/attributes.rb +29 -0
  17. data/lib/erector/cache.rb +37 -0
  18. data/lib/erector/caching.rb +65 -0
  19. data/lib/erector/convenience.rb +98 -0
  20. data/lib/erector/dependencies.rb +24 -0
  21. data/lib/erector/dependency.rb +31 -0
  22. data/lib/erector/element.rb +113 -0
  23. data/lib/erector/externals.rb +104 -0
  24. data/lib/erector/html.rb +12 -0
  25. data/lib/erector/html_widget.rb +220 -0
  26. data/lib/erector/inline.rb +37 -0
  27. data/lib/erector/jquery.rb +28 -0
  28. data/lib/erector/mixin.rb +12 -0
  29. data/lib/erector/needs.rb +95 -0
  30. data/lib/erector/output.rb +144 -0
  31. data/lib/erector/promise.rb +141 -0
  32. data/lib/erector/rails/form_builder.rb +44 -0
  33. data/lib/erector/rails/railtie.rb +13 -0
  34. data/lib/erector/rails/template_handler.rb +16 -0
  35. data/lib/erector/rails/widget_renderer.rb +6 -0
  36. data/lib/erector/rails.rb +221 -0
  37. data/lib/erector/raw_string.rb +12 -0
  38. data/lib/erector/sass.rb +32 -0
  39. data/lib/erector/tag.rb +66 -0
  40. data/lib/erector/text.rb +123 -0
  41. data/lib/erector/unicode.rb +18185 -0
  42. data/lib/erector/unicode_builder.rb +67 -0
  43. data/lib/erector/version.rb +5 -0
  44. data/lib/erector/widget.rb +94 -0
  45. data/lib/erector/widgets.rb +5 -0
  46. data/lib/erector/xml_widget.rb +131 -0
  47. data/lib/erector.rb +28 -0
  48. data/spec/dummy/Rakefile +7 -0
  49. data/spec/dummy/app/controllers/application.rb +6 -0
  50. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  51. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  52. data/spec/dummy/app/views/layouts/erb_as_layout.html.erb +2 -0
  53. data/spec/dummy/app/views/layouts/widget_as_layout.rb +8 -0
  54. data/spec/dummy/app/views/test/_erb.erb +1 -0
  55. data/spec/dummy/app/views/test/_erector.rb +5 -0
  56. data/spec/dummy/app/views/test/_partial_with_locals.rb +7 -0
  57. data/spec/dummy/app/views/test/bare.rb +5 -0
  58. data/spec/dummy/app/views/test/erb_from_erector.html.rb +5 -0
  59. data/spec/dummy/app/views/test/erector_from_erb.html.erb +1 -0
  60. data/spec/dummy/app/views/test/erector_with_locals_from_erb.html.erb +6 -0
  61. data/spec/dummy/app/views/test/implicit_assigns.html.rb +5 -0
  62. data/spec/dummy/app/views/test/needs.html.rb +7 -0
  63. data/spec/dummy/app/views/test/needs_subclass.html.rb +5 -0
  64. data/spec/dummy/app/views/test/protected_instance_variable.html.rb +5 -0
  65. data/spec/dummy/app/views/test/render_default.html.rb +5 -0
  66. data/spec/dummy/app/views/test/render_default_erb_with_layout.html.erb +1 -0
  67. data/spec/dummy/app/views/test/render_default_widget_with_layout.html.rb +5 -0
  68. data/spec/dummy/app/views/test/render_partial.html.rb +5 -0
  69. data/spec/dummy/app/views/test/render_with_widget_as_layout.rb +5 -0
  70. data/spec/dummy/app/views/test/render_with_widget_as_layout_using_content_for.rb +8 -0
  71. data/spec/dummy/config/application.rb +44 -0
  72. data/spec/dummy/config/boot.rb +10 -0
  73. data/spec/dummy/config/database.yml +22 -0
  74. data/spec/dummy/config/environment.rb +5 -0
  75. data/spec/dummy/config/environments/development.rb +22 -0
  76. data/spec/dummy/config/environments/production.rb +49 -0
  77. data/spec/dummy/config/environments/test.rb +36 -0
  78. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  79. data/spec/dummy/config/initializers/inflections.rb +10 -0
  80. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  81. data/spec/dummy/config/initializers/secret_token.rb +12 -0
  82. data/spec/dummy/config/initializers/session_store.rb +8 -0
  83. data/spec/dummy/config/locales/en.yml +5 -0
  84. data/spec/dummy/config/routes.rb +3 -0
  85. data/spec/dummy/config.ru +4 -0
  86. data/spec/dummy/db/seeds.rb +7 -0
  87. data/spec/dummy/script/rails +6 -0
  88. data/spec/dummy/spec/form_builder_spec.rb +21 -0
  89. data/spec/dummy/spec/rails_helpers_spec.rb +236 -0
  90. data/spec/dummy/spec/rails_spec_helper.rb +10 -0
  91. data/spec/dummy/spec/rails_widget_spec.rb +83 -0
  92. data/spec/dummy/spec/render_spec.rb +369 -0
  93. data/spec/erector/after_initialize_spec.rb +45 -0
  94. data/spec/erector/cache_spec.rb +133 -0
  95. data/spec/erector/caching_spec.rb +184 -0
  96. data/spec/erector/convenience_spec.rb +250 -0
  97. data/spec/erector/dependency_spec.rb +67 -0
  98. data/spec/erector/hello_from_readme.rb +18 -0
  99. data/spec/erector/hello_from_readme_spec.rb +11 -0
  100. data/spec/erector/html_spec.rb +585 -0
  101. data/spec/erector/indentation_spec.rb +211 -0
  102. data/spec/erector/inline_spec.rb +94 -0
  103. data/spec/erector/jquery_spec.rb +35 -0
  104. data/spec/erector/mixin_spec.rb +65 -0
  105. data/spec/erector/needs_spec.rb +141 -0
  106. data/spec/erector/output_spec.rb +293 -0
  107. data/spec/erector/promise_spec.rb +173 -0
  108. data/spec/erector/sample-file.txt +1 -0
  109. data/spec/erector/sass_spec.rb +57 -0
  110. data/spec/erector/tag_spec.rb +67 -0
  111. data/spec/erector/unicode_builder_spec.rb +75 -0
  112. data/spec/erector/widget_spec.rb +310 -0
  113. data/spec/erector/xml_widget_spec.rb +73 -0
  114. data/spec/spec_helper.rb +31 -0
  115. metadata +368 -0
@@ -0,0 +1,45 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../spec_helper")
2
+
3
+ class AfterInitializeWidget < Erector::Widget
4
+
5
+ after_initialize do
6
+ @foo ||= ''
7
+ @foo += 'bar'
8
+ end
9
+
10
+ def content
11
+ html do
12
+ head do
13
+ title "Welcome page"
14
+ end
15
+ body do
16
+ p @foo
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ class AfterInitializeWidgetTwo < AfterInitializeWidget
23
+ end
24
+
25
+ class AfterInitializeWidgetThree < AfterInitializeWidget
26
+ after_initialize do
27
+ @foo += 'baz'
28
+ end
29
+ end
30
+
31
+ describe Erector::AfterInitialize do
32
+
33
+ it 'should call the block' do
34
+ AfterInitializeWidget.new.to_html.should == %Q{<html><head><title>Welcome page</title></head><body><p>bar</p></body></html>}
35
+ end
36
+
37
+ it 'should call the block only once' do
38
+ AfterInitializeWidgetTwo.new.to_html.should == %Q{<html><head><title>Welcome page</title></head><body><p>bar</p></body></html>}
39
+ end
40
+
41
+ it 'should call each block' do
42
+ AfterInitializeWidgetThree.new.to_html.should == %Q{<html><head><title>Welcome page</title></head><body><p>barbaz</p></body></html>}
43
+ end
44
+
45
+ end
@@ -0,0 +1,133 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../spec_helper")
2
+
3
+ # todo: figure out why "include Caching" only works when it's on Widget
4
+ describe Erector::Cache do
5
+ before do
6
+ ::Rails.cache.clear
7
+ @cache = Erector::Cache.instance
8
+ end
9
+
10
+ class Johnny < Erector::Widget
11
+ end
12
+
13
+ class June < Erector::Widget
14
+ end
15
+
16
+ it 'caches a class with no parameters' do
17
+ @cache[Johnny] = "ring of fire"
18
+ @cache[Johnny].should == "ring of fire"
19
+ end
20
+
21
+ it 'caches two classes with no parameters' do
22
+ @cache[Johnny] = "ring of fire"
23
+ @cache[June] = "wildwood flower"
24
+ @cache[Johnny].should == "ring of fire"
25
+ @cache[June].should == "wildwood flower"
26
+ end
27
+
28
+ it "stores different slots for the same class with different parameters" do
29
+ @cache[Johnny, {:flames => "higher"}] = "ring of fire"
30
+ @cache[Johnny, {:working => "in a coal mine"}] = "my daddy died young"
31
+
32
+ @cache[Johnny, {:flames => "higher"}].should == "ring of fire"
33
+ @cache[Johnny, {:working => "in a coal mine"}].should == "my daddy died young"
34
+ end
35
+
36
+ it "stores different slots for the same class with same parameters and different content methods" do
37
+ @cache[Johnny, {}, :foo] = "ring of fire"
38
+ @cache[Johnny, {}, :bar] = "my daddy died young"
39
+
40
+ @cache[Johnny, {}, :foo].should == "ring of fire"
41
+ @cache[Johnny, {}, :bar].should == "my daddy died young"
42
+ end
43
+
44
+ describe 'after storing a widget with one parameter' do
45
+ before do
46
+ @cache[Johnny, {:flames => "higher"}] = "ring of fire"
47
+ end
48
+
49
+ it 'doesn\'t get it when passed the class alone' do
50
+ @cache[Johnny].should be_nil
51
+ end
52
+
53
+ it 'doesn\'t get it when passed a different class' do
54
+ @cache[June].should be_nil
55
+ end
56
+
57
+ it 'gets it' do
58
+ @cache[Johnny, {:flames => "higher"}].should == "ring of fire"
59
+ end
60
+
61
+ it 'doesn\'t get it when passed a different parameter key' do
62
+ @cache[Johnny, {:working => "coal mine"}].should be_nil
63
+ end
64
+
65
+ it 'doesn\'t get it when passed a different parameter value' do
66
+ @cache[Johnny, {:flames => "lower"}].should be_nil
67
+ end
68
+
69
+ it 'doesn\'t get it when passed an extra parameter key' do
70
+ @cache[Johnny, {:flames => "higher", :working => "coal mine"}].should be_nil
71
+ end
72
+ end
73
+
74
+ describe 'after storing a widget with more than one parameter' do
75
+ before do
76
+ @cache[Johnny, {:flames => "higher", :working => "coal mine"}] = "ring of fire"
77
+ end
78
+
79
+ it "gets it" do
80
+ @cache[Johnny, {:flames => "higher", :working => "coal mine"}].should == "ring of fire"
81
+ end
82
+
83
+ it 'doesn\'t get it when passed the class alone' do
84
+ @cache[Johnny].should be_nil
85
+ end
86
+
87
+ it "doesn't get it when passed a partial parameter set" do
88
+ @cache[Johnny, {:flames => "higher"}].should be_nil
89
+ end
90
+
91
+ it 'doesn\'t get it when passed a different class' do
92
+ @cache[June].should be_nil
93
+ end
94
+
95
+ it 'doesn\'t get it when passed different a parameter value' do
96
+ @cache[Johnny, {:flames => "lower", :working => "coal mine"}].should be_nil
97
+ end
98
+
99
+ it 'doesn\'t get it when passed an extra parameter key' do
100
+ @cache[Johnny, {:flames => "higher", :working => "coal mine", :hear => "train a' comin'"}].should be_nil
101
+ end
102
+ end
103
+
104
+ describe "expires" do
105
+ it 'a class with no parameters' do
106
+ @cache[Johnny] = "ring of fire"
107
+ @cache.delete(Johnny)
108
+ @cache[Johnny].should be_nil
109
+ end
110
+
111
+ it 'all versions of a class' do
112
+ @cache[Johnny] = "i fell in"
113
+ @cache[Johnny, {:flames => "higher"}] = "ring of fire"
114
+ @cache[Johnny, {:working => "in a coal mine"}] = "my daddy died young"
115
+
116
+ ::Rails.cache.clear
117
+
118
+ @cache[Johnny].should be_nil
119
+ @cache[Johnny, {:flames => "higher"}].should be_nil
120
+ @cache[Johnny, {:working => "in a coal mine"}].should be_nil
121
+ end
122
+
123
+ it '...but not other cached values' do
124
+ @cache[Johnny] = "ring of fire"
125
+ @cache[Johnny, {:flames => 'higher'}] = "higher fire"
126
+ @cache[June] = "wildwood flower"
127
+ @cache.delete(Johnny)
128
+ @cache[Johnny].should be_nil
129
+ @cache[Johnny, {:flames => 'higher'}].should == "higher fire"
130
+ @cache[June].should == "wildwood flower"
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,184 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../spec_helper")
2
+
3
+ describe Erector::Caching do
4
+ include Erector::Mixin
5
+
6
+ class Cash < Erector::Widget
7
+ needs :name
8
+ cachable # this is correct, just an alias
9
+
10
+ def content
11
+ p do
12
+ text @name
13
+ text " Cash"
14
+ end
15
+ end
16
+ end
17
+
18
+ class CashWithVersion < Erector::Widget
19
+ needs :name
20
+ cachable 'v2'
21
+
22
+ def content
23
+ p do
24
+ text @name
25
+ text " Cash 2"
26
+ end
27
+ end
28
+ end
29
+
30
+ class CashWithComplexKey < Erector::Widget
31
+ needs :sites
32
+ cachable
33
+
34
+ def content
35
+ text @sites.first.name
36
+ end
37
+ end
38
+
39
+ class Family < Erector::Widget
40
+ cacheable
41
+
42
+ def content
43
+ widget Cash, :name => "Johnny"
44
+ widget Cash, :name => "June"
45
+ end
46
+ end
47
+
48
+ class ModelCash < Erector::Widget
49
+ cacheable
50
+
51
+ def content
52
+ text @model.name
53
+ end
54
+ end
55
+
56
+ class NotCachable < Erector::Widget
57
+ def content
58
+ text "CONTENT"
59
+ end
60
+ end
61
+
62
+ before do
63
+ ::Rails.cache.clear
64
+ @cache = Erector::Cache.instance
65
+ end
66
+
67
+ it "has a global cache" do
68
+ Erector::Widget.cache.should == @cache
69
+ end
70
+
71
+ it '-- a widget is not cachable by default' do
72
+ Erector::Widget.cachable?.should be_false
73
+ end
74
+
75
+ it '-- a widget is cachable if you say so in the class definition' do
76
+ Cash.cachable?.should be_true
77
+ end
78
+
79
+ it '-- can be declared cachable using the alternate spelling "cacheable"' do
80
+ Family.cachable?.should be_true
81
+ end
82
+
83
+ describe '#to_html' do
84
+
85
+ it "caches a rendered widget" do
86
+ Cash.new(:name => "Johnny").to_html
87
+ @cache[Cash, {:name => "Johnny"}].should == "<p>Johnny Cash</p>"
88
+ end
89
+
90
+ it "uses a cache version for the class" do
91
+ CashWithVersion.new(:name => "Johnny").to_html
92
+ @cache[CashWithVersion, 'v2', {:name => "Johnny"}].should == "<p>Johnny Cash 2</p>"
93
+ end
94
+
95
+ it "handles complex keys" do
96
+ site1 = OpenStruct.new(name: 'site one name')
97
+ site2 = OpenStruct.new(name: 'site two name')
98
+ site3 = OpenStruct.new(name: 'site three name')
99
+ CashWithComplexKey.new(sites: [site1, site2]).to_html
100
+ @cache[CashWithComplexKey, sites: [site1, site2]].should == "site one name"
101
+ CashWithComplexKey.new(sites: [site3, site1, site2]).to_html.should == "site three name"
102
+ end
103
+
104
+ it "calls :cache_key" do
105
+ model = OpenStruct.new(name: 'Myname', cache_key: 'two')
106
+ ModelCash.new(:model => model).to_html
107
+ @cache[ModelCash, { model: 'two' }].should == "Myname"
108
+ end
109
+
110
+ it "uses the cached value" do
111
+ @cache[Cash, {:name => "Johnny"}] = "CACHED"
112
+ Cash.new(:name => "Johnny").to_html.should == "CACHED"
113
+ end
114
+
115
+ it "doesn't use the cached value for widgets not declared cachable" do
116
+ @cache[NotCachable] = "CACHED"
117
+ NotCachable.new.to_html.should == "CONTENT"
118
+ end
119
+
120
+ it "doesn't cache widgets not declared cachable" do
121
+ NotCachable.new.to_html
122
+ @cache[NotCachable].should be_nil
123
+ end
124
+
125
+ it "doesn't cache widgets initialized with a block (yet)" do
126
+ Cash.new(:name => "June") do
127
+ text "whatever"
128
+ end.to_html
129
+ @cache[Cash, {:name => "June"}].should be_nil
130
+ end
131
+
132
+ it "caches distinct values when using :content_method_name" do
133
+ widget = Class.new(Erector::Widget) do
134
+ cacheable
135
+
136
+ def foo
137
+ text "foo"
138
+ end
139
+
140
+ def bar
141
+ text "bar"
142
+ end
143
+ end
144
+
145
+ widget.new.to_html(:content_method_name => :foo).should == "foo"
146
+ widget.new.to_html(:content_method_name => :bar).should == "bar"
147
+ end
148
+
149
+ it "works when passing an existing output as a parameter to to_html" do
150
+ pending
151
+ end
152
+ end
153
+
154
+ describe '#widget' do
155
+
156
+ it "caches rendered widgets" do
157
+ Family.new.to_html
158
+ @cache[Cash, {:name => "Johnny"}].to_s.should == "<p>Johnny Cash</p>"
159
+ @cache[Cash, {:name => "June"}].to_s.should == "<p>June Cash</p>"
160
+ end
161
+
162
+ it "uses the cached value" do
163
+ @cache[Cash, {:name => "Johnny"}] = "JOHNNY CACHED"
164
+ Family.new.to_html.should == "JOHNNY CACHED<p>June Cash</p>"
165
+ end
166
+
167
+ class WidgetWithBlock < Erector::Widget
168
+ def content
169
+ call_block
170
+ end
171
+ end
172
+
173
+ it "doesn't cache widgets initialized with a block (yet)" do
174
+ erector {
175
+ w = WidgetWithBlock.new do
176
+ text "in block"
177
+ end
178
+ widget w
179
+ }.should == "in block"
180
+ @cache[WidgetWithBlock].should be_nil
181
+ end
182
+
183
+ end
184
+ end
@@ -0,0 +1,250 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../spec_helper")
2
+
3
+ describe Erector::Convenience do
4
+ include Erector::Mixin
5
+
6
+ describe "#to_pretty" do
7
+ it "calls render with :prettyprint => true" do
8
+ widget = Erector.inline do
9
+ div 'foo'
10
+ div 'boo'
11
+ end
12
+ widget.to_pretty.should == "<div>foo</div>\n<div>boo</div>\n"
13
+ end
14
+
15
+ it "passes extra options through to render" do
16
+ pending "RR problem with Ruby 1.9" if RUBY_VERSION >= "1.9.0"
17
+ widget = Erector.inline do
18
+ div "foo"
19
+ end
20
+ mock(widget).emit({:prettyprint => true, :extra => "yay"})
21
+ widget.to_pretty(:extra => "yay")
22
+ end
23
+ end
24
+
25
+ describe "#to_html" do
26
+ it "returns html" do
27
+ Erector.inline do
28
+ div "foo"
29
+ end.to_html.should == "<div>foo</div>"
30
+ end
31
+ end
32
+
33
+ describe "#to_text" do
34
+ it "strips tags" do
35
+ Erector.inline do
36
+ div "foo"
37
+ end.to_text.should == "foo"
38
+ end
39
+
40
+ it "unescapes named entities" do
41
+ s = "my \"dog\" has fleas & <ticks>"
42
+ Erector.inline do
43
+ text s
44
+ end.to_text.should == s
45
+ end
46
+
47
+ it "ignores >s inside attribute strings" do
48
+ Erector.inline do
49
+ a "foo", :href => "http://example.com/x>y"
50
+ end.to_text.should == "foo"
51
+ end
52
+
53
+ def with_prettyprint_default(value = true)
54
+ old_default = Erector::Widget.new.prettyprint_default
55
+ begin
56
+ Erector::Widget.prettyprint_default = value
57
+ yield
58
+ ensure
59
+ Erector::Widget.prettyprint_default = old_default
60
+ end
61
+ end
62
+
63
+ it "doesn't inherit unwanted pretty-printed whitespace (i.e. it turns off prettyprinting)" do
64
+ with_prettyprint_default(true) do
65
+ Erector.inline do
66
+ div { div { div "foo" } }
67
+ end.to_text.should == "foo"
68
+ end
69
+ end
70
+
71
+ it "passes extra attributes through to to_s" do
72
+ class Funny < Erector::Widget
73
+ def content
74
+ div "foo"
75
+ end
76
+
77
+ def funny
78
+ div "haha"
79
+ end
80
+ end
81
+ Funny.new.to_text(:content_method_name => :funny).should == "haha"
82
+ end
83
+
84
+ it "doesn't turn a p into a newline if it's at the beginning of the string" do
85
+ Erector.inline do
86
+ p "hi"
87
+ end.to_text.should == "hi\n"
88
+ end
89
+
90
+ it "puts a blank line (two newlines) after a /p tag" do
91
+ Erector.inline do
92
+ p "first paragraph"
93
+ p "second paragraph"
94
+ end.to_text.should == "first paragraph\n\nsecond paragraph\n"
95
+ end
96
+
97
+ it "separates p tags with attributes" do
98
+ Erector.inline do
99
+ p "first paragraph", :class => "first"
100
+ p "second paragraph", :class => "second"
101
+ end.to_text.should == "first paragraph\n\nsecond paragraph\n"
102
+ end
103
+
104
+ it "puts a newline after a br tag" do
105
+ Erector.inline do
106
+ text "first line"
107
+ br
108
+ text "second line"
109
+ end.to_text.should == "first line\nsecond line"
110
+ end
111
+
112
+ it "formats a UL (unordered list) using asterisks for bullets" do
113
+ Erector.inline do
114
+ ul do
115
+ li "vanilla"
116
+ li "chocolate"
117
+ li "strawberry"
118
+ end
119
+ end.to_text.should == "\n* vanilla\n* chocolate\n* strawberry\n"
120
+ end
121
+
122
+ # it's too hard to keep track of numbers with a regexp munger, so just use asterisks for bullets
123
+ # todo: integrate text output into core rendering code
124
+ it "formats an OL (ordered list)" do
125
+ Erector.inline do
126
+ ol do
127
+ li "vanilla"
128
+ li "chocolate"
129
+ li "strawberry"
130
+ end
131
+ end.to_text.should == "\n* vanilla\n* chocolate\n* strawberry\n"
132
+ end
133
+ end
134
+
135
+ describe "#join" do
136
+ it "empty array means nothing to join" do
137
+ erector do
138
+ join [], Erector::Widget.new { text "x" }
139
+ end.should == ""
140
+ end
141
+
142
+ it "larger example with two tabs" do
143
+ erector do
144
+ tab1 =
145
+ Erector.inline do
146
+ a "Upload document", :href => "/upload"
147
+ end
148
+ tab2 =
149
+ Erector.inline do
150
+ a "Logout", :href => "/logout"
151
+ end
152
+ join [tab1, tab2],
153
+ Erector::Widget.new { text nbsp(" |"); text " " }
154
+ end.should ==
155
+ '<a href="/upload">Upload document</a>&#160;| <a href="/logout">Logout</a>'
156
+ end
157
+
158
+ it "plain string as join separator means pass it to text" do
159
+ erector do
160
+ join [
161
+ Erector::Widget.new { text "x" },
162
+ Erector::Widget.new { text "y" }
163
+ ], "<>"
164
+ end.should == "x&lt;&gt;y"
165
+ end
166
+
167
+ it "plain string as item to join means pass it to text" do
168
+ erector do
169
+ join [
170
+ "<",
171
+ "&"
172
+ ], Erector::Widget.new { text " + " }
173
+ end.should == "&lt; + &amp;"
174
+ end
175
+ end
176
+
177
+ describe "#css" do
178
+ it "makes a link when passed a string" do
179
+ erector do
180
+ css "erector.css"
181
+ end.should == "<link rel=\"stylesheet\" type=\"text/css\" href=\"erector.css\" />"
182
+ end
183
+
184
+ it "accepts a media attribute" do
185
+ erector do
186
+ css "print.css", :media => "print"
187
+ end.should == "<link rel=\"stylesheet\" type=\"text/css\" href=\"print.css\" media=\"print\" />"
188
+ end
189
+
190
+ it "passes extra attributes through" do
191
+ erector { css "foo.css", :title => 'Foo' }.should ==
192
+ "<link rel=\"stylesheet\" type=\"text/css\" href=\"foo.css\" title=\"Foo\" />"
193
+ end
194
+ end
195
+
196
+ describe "#url" do
197
+ it "renders an anchor tag with the same href and text" do
198
+ erector do
199
+ url "http://example.com"
200
+ end.should == "<a href=\"http://example.com\">http://example.com</a>"
201
+ end
202
+
203
+ it "accepts extra attributes" do
204
+ erector do
205
+ url "http://example.com", :onclick=>"alert('foo')".html_safe
206
+ end.should == "<a href=\"http://example.com\" onclick=\"alert('foo')\">http://example.com</a>"
207
+ end
208
+
209
+ end
210
+
211
+ describe "#dom_id" do
212
+ class DOMIDWidget < Erector::Widget
213
+ def content
214
+ div :id => dom_id
215
+ end
216
+ end
217
+
218
+ it "makes a unique id based on the widget's class name and object id" do
219
+ widget = DOMIDWidget.new
220
+ widget.dom_id.should include("#{widget.object_id}")
221
+ widget.dom_id.should include("DOMIDWidget")
222
+ end
223
+
224
+ it "can be used as an HTML id" do
225
+ widget = DOMIDWidget.new
226
+ widget.to_html.should == "<div id=\"#{widget.dom_id}\"></div>"
227
+ end
228
+
229
+ describe 'for a namespaced widget class' do
230
+
231
+ module ::ErectorConvenienceSpec
232
+ class NestedWidget < Erector::Widget
233
+ end
234
+ end
235
+
236
+ it 'is colon escaped' do
237
+ g = ErectorConvenienceSpec::NestedWidget.new
238
+ g.dom_id.should_not =~ /:/
239
+ end
240
+
241
+ it 'combines all parent namespaces' do
242
+ g = ErectorConvenienceSpec::NestedWidget.new
243
+ g.dom_id.should == "ErectorConvenienceSpec_NestedWidget_#{g.object_id}"
244
+ end
245
+
246
+ end
247
+
248
+ end
249
+ end
250
+