spontaneous 0.2.0.beta4 → 0.2.0.beta5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (205) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +39 -0
  3. data/Gemfile +11 -6
  4. data/Readme.markdown +136 -69
  5. data/application/css/core.css.scss +27 -7
  6. data/application/css/editing.css.scss +4 -26
  7. data/application/css/schema_error.css.scss +22 -0
  8. data/application/js/content.js +11 -3
  9. data/application/js/edit_panel.js +1 -4
  10. data/application/js/field/file.js +17 -0
  11. data/application/js/field/image.js +30 -21
  12. data/application/js/field/string.js +4 -1
  13. data/application/js/field_preview.js +21 -16
  14. data/application/js/publish.js +6 -6
  15. data/application/js/types.js +5 -13
  16. data/application/js/views.js +2 -2
  17. data/application/js/views/box_view.js +3 -2
  18. data/application/js/views/page_piece_view.js +1 -1
  19. data/application/js/views/piece_view.js +1 -1
  20. data/application/views/schema_modification_error.html.erb +13 -3
  21. data/db/migrations/20131104101935_site_must_publish_all.rb +14 -0
  22. data/lib/spontaneous.rb +0 -1
  23. data/lib/spontaneous/box_style.rb +15 -9
  24. data/lib/spontaneous/capistrano/deploy.rb +13 -1
  25. data/lib/spontaneous/change.rb +11 -13
  26. data/lib/spontaneous/cli.rb +5 -2
  27. data/lib/spontaneous/cli/assets.rb +7 -1
  28. data/lib/spontaneous/cli/console.rb +7 -1
  29. data/lib/spontaneous/cli/content.rb +35 -0
  30. data/lib/spontaneous/cli/fields.rb +3 -2
  31. data/lib/spontaneous/cli/generate.rb +5 -2
  32. data/lib/spontaneous/cli/server.rb +12 -8
  33. data/lib/spontaneous/cli/site.rb +12 -12
  34. data/lib/spontaneous/cli/user.rb +28 -14
  35. data/lib/spontaneous/collections/box_set.rb +4 -4
  36. data/lib/spontaneous/collections/field_set.rb +4 -4
  37. data/lib/spontaneous/collections/prototype_set.rb +12 -4
  38. data/lib/spontaneous/data_mapper.rb +11 -7
  39. data/lib/spontaneous/data_mapper/content_model.rb +8 -0
  40. data/lib/spontaneous/data_mapper/content_model/associations.rb +1 -1
  41. data/lib/spontaneous/data_mapper/dataset.rb +14 -2
  42. data/lib/spontaneous/data_mapper/scope.rb +33 -13
  43. data/lib/spontaneous/facet.rb +4 -0
  44. data/lib/spontaneous/field.rb +12 -12
  45. data/lib/spontaneous/field/base.rb +27 -22
  46. data/lib/spontaneous/field/boolean.rb +4 -4
  47. data/lib/spontaneous/field/date.rb +2 -2
  48. data/lib/spontaneous/field/file.rb +24 -18
  49. data/lib/spontaneous/field/html.rb +1 -1
  50. data/lib/spontaneous/field/image.rb +6 -19
  51. data/lib/spontaneous/field/location.rb +1 -1
  52. data/lib/spontaneous/field/long_string.rb +3 -3
  53. data/lib/spontaneous/field/markdown.rb +3 -3
  54. data/lib/spontaneous/field/select.rb +2 -2
  55. data/lib/spontaneous/field/string.rb +2 -2
  56. data/lib/spontaneous/field/tags.rb +2 -2
  57. data/lib/spontaneous/field/update.rb +21 -20
  58. data/lib/spontaneous/field/webvideo.rb +6 -6
  59. data/lib/spontaneous/field/webvideo/fallback.rb +2 -2
  60. data/lib/spontaneous/field/webvideo/vimeo.rb +7 -7
  61. data/lib/spontaneous/generators/site.rb +2 -2
  62. data/lib/spontaneous/generators/site/Gemfile.tt +5 -1
  63. data/lib/spontaneous/layout.rb +2 -2
  64. data/lib/spontaneous/media.rb +1 -0
  65. data/lib/spontaneous/media/file.rb +6 -5
  66. data/lib/spontaneous/media/image/attributes.rb +4 -0
  67. data/lib/spontaneous/media/image/renderable.rb +4 -4
  68. data/lib/spontaneous/media/store.rb +22 -0
  69. data/lib/spontaneous/{storage → media/store}/backend.rb +1 -1
  70. data/lib/spontaneous/{storage → media/store}/cloud.rb +1 -1
  71. data/lib/spontaneous/{storage → media/store}/local.rb +1 -1
  72. data/lib/spontaneous/media/temp_file.rb +1 -1
  73. data/lib/spontaneous/model.rb +10 -7
  74. data/lib/spontaneous/model/action.rb +7 -0
  75. data/lib/spontaneous/model/action/clean.rb +87 -0
  76. data/lib/spontaneous/model/box/allowed_types.rb +15 -1
  77. data/lib/spontaneous/model/core.rb +10 -0
  78. data/lib/spontaneous/model/core/aliases.rb +1 -1
  79. data/lib/spontaneous/model/core/content_groups.rb +1 -1
  80. data/lib/spontaneous/model/core/fields.rb +1 -1
  81. data/lib/spontaneous/model/core/modifications.rb +2 -2
  82. data/lib/spontaneous/model/core/page_search.rb +4 -0
  83. data/lib/spontaneous/model/core/publishing.rb +4 -17
  84. data/lib/spontaneous/model/core/render.rb +4 -4
  85. data/lib/spontaneous/model/core/styles.rb +2 -2
  86. data/lib/spontaneous/model/core/visibility.rb +6 -2
  87. data/lib/spontaneous/model/page.rb +6 -2
  88. data/lib/spontaneous/model/page/controllers.rb +55 -17
  89. data/lib/spontaneous/model/page/formats.rb +12 -7
  90. data/lib/spontaneous/model/page/layouts.rb +2 -2
  91. data/lib/spontaneous/model/page/locks.rb +4 -1
  92. data/lib/spontaneous/model/page/page_tree.rb +40 -6
  93. data/lib/spontaneous/output.rb +14 -52
  94. data/lib/spontaneous/output/context.rb +11 -39
  95. data/lib/spontaneous/output/context/navigation.rb +31 -0
  96. data/lib/spontaneous/output/format.rb +15 -19
  97. data/lib/spontaneous/output/renderable.rb +99 -0
  98. data/lib/spontaneous/output/store.rb +24 -0
  99. data/lib/spontaneous/output/store/backend.rb +52 -0
  100. data/lib/spontaneous/output/store/file.rb +77 -0
  101. data/lib/spontaneous/output/store/moneta.rb +117 -0
  102. data/lib/spontaneous/output/store/revision.rb +34 -0
  103. data/lib/spontaneous/output/store/store.rb +15 -0
  104. data/lib/spontaneous/output/store/transaction.rb +44 -0
  105. data/lib/spontaneous/output/template/engine.rb +17 -7
  106. data/lib/spontaneous/output/template/renderer.rb +66 -40
  107. data/lib/spontaneous/page_lock.rb +5 -7
  108. data/lib/spontaneous/page_piece.rb +2 -2
  109. data/lib/spontaneous/permissions/user.rb +14 -7
  110. data/lib/spontaneous/plugins/application/features.rb +8 -4
  111. data/lib/spontaneous/plugins/application/state.rb +12 -6
  112. data/lib/spontaneous/prototypes/box_prototype.rb +9 -10
  113. data/lib/spontaneous/prototypes/field_prototype.rb +66 -15
  114. data/lib/spontaneous/publishing/immediate.rb +30 -26
  115. data/lib/spontaneous/rack.rb +12 -7
  116. data/lib/spontaneous/rack/back.rb +43 -37
  117. data/lib/spontaneous/rack/back/base.rb +4 -4
  118. data/lib/spontaneous/rack/back/changes.rb +2 -2
  119. data/lib/spontaneous/rack/back/file.rb +16 -24
  120. data/lib/spontaneous/rack/back/map.rb +5 -5
  121. data/lib/spontaneous/rack/back/preview.rb +3 -4
  122. data/lib/spontaneous/rack/back/schema.rb +1 -1
  123. data/lib/spontaneous/rack/back/site.rb +6 -7
  124. data/lib/spontaneous/rack/front.rb +19 -16
  125. data/lib/spontaneous/rack/middleware/authenticate.rb +3 -3
  126. data/lib/spontaneous/rack/middleware/reloader.rb +3 -2
  127. data/lib/spontaneous/rack/middleware/scope.rb +25 -19
  128. data/lib/spontaneous/rack/page_controller.rb +164 -13
  129. data/lib/spontaneous/rack/public.rb +23 -62
  130. data/lib/spontaneous/rack/static.rb +2 -3
  131. data/lib/spontaneous/schema.rb +27 -8
  132. data/lib/spontaneous/schema/schema_modification.rb +9 -1
  133. data/lib/spontaneous/schema/uid.rb +2 -2
  134. data/lib/spontaneous/schema/uid_map.rb +3 -2
  135. data/lib/spontaneous/search/database.rb +2 -2
  136. data/lib/spontaneous/search/field.rb +5 -3
  137. data/lib/spontaneous/search/index.rb +12 -7
  138. data/lib/spontaneous/search/results.rb +5 -3
  139. data/lib/spontaneous/server.rb +2 -2
  140. data/lib/spontaneous/site.rb +10 -3
  141. data/lib/spontaneous/site/features.rb +26 -6
  142. data/lib/spontaneous/site/helpers.rb +9 -12
  143. data/lib/spontaneous/site/level.rb +7 -9
  144. data/lib/spontaneous/site/map.rb +9 -11
  145. data/lib/spontaneous/site/paths.rb +5 -5
  146. data/lib/spontaneous/site/publishing.rb +83 -80
  147. data/lib/spontaneous/site/schema.rb +1 -7
  148. data/lib/spontaneous/site/search.rb +8 -18
  149. data/lib/spontaneous/site/selectors.rb +60 -54
  150. data/lib/spontaneous/site/state.rb +36 -30
  151. data/lib/spontaneous/site/storage.rb +10 -16
  152. data/lib/spontaneous/state.rb +8 -0
  153. data/lib/spontaneous/style.rb +32 -33
  154. data/lib/spontaneous/version.rb +1 -1
  155. data/spontaneous.gemspec +22 -21
  156. data/test/fixtures/public/templates/layouts/default.html.cut +1 -1
  157. data/test/fixtures/public/templates/layouts/default.pdf.cut +1 -1
  158. data/test/fixtures/public/templates/layouts/default.rss.cut +1 -1
  159. data/test/fixtures/search/config/indexes.rb +1 -1
  160. data/test/fixtures/serialisation/class_hash.yaml.erb +13 -1
  161. data/test/fixtures/serialisation/root_hash.yaml.erb +10 -0
  162. data/test/functional/test_application.rb +20 -24
  163. data/test/functional/test_back.rb +26 -27
  164. data/test/functional/test_cli.rb +146 -0
  165. data/test/functional/test_front.rb +287 -216
  166. data/test/functional/test_user_manager.rb +1 -1
  167. data/test/test_helper.rb +15 -11
  168. data/test/unit/test_alias.rb +32 -25
  169. data/test/unit/test_asset_bundler.rb +1 -1
  170. data/test/unit/test_assets.rb +34 -33
  171. data/test/unit/test_authentication.rb +1 -1
  172. data/test/unit/test_boxes.rb +16 -2
  173. data/test/unit/test_changesets.rb +23 -11
  174. data/test/unit/test_content.rb +15 -0
  175. data/test/unit/test_context.rb +139 -0
  176. data/test/unit/test_controllers.rb +374 -0
  177. data/test/{experimental → unit}/test_crypt.rb +0 -0
  178. data/test/unit/test_datamapper.rb +260 -237
  179. data/test/unit/test_datamapper_content.rb +42 -12
  180. data/test/{experimental → unit}/test_features.rb +85 -3
  181. data/test/unit/test_fields.rb +117 -42
  182. data/test/unit/test_formats.rb +11 -1
  183. data/test/unit/test_generators.rb +2 -2
  184. data/test/unit/test_helpers.rb +7 -8
  185. data/test/unit/test_images.rb +39 -2
  186. data/test/unit/test_layouts.rb +14 -12
  187. data/test/unit/test_media.rb +32 -23
  188. data/test/unit/test_output_store.rb +342 -0
  189. data/test/unit/test_page.rb +8 -1
  190. data/test/unit/test_permissions.rb +11 -7
  191. data/test/unit/test_plugins.rb +3 -3
  192. data/test/unit/test_prototype_set.rb +8 -1
  193. data/test/unit/test_publishing.rb +67 -54
  194. data/test/unit/test_render.rb +91 -38
  195. data/test/unit/test_revisions.rb +4 -4
  196. data/test/unit/test_schema.rb +109 -84
  197. data/test/unit/test_search.rb +42 -42
  198. data/test/unit/test_serialisation.rb +3 -2
  199. data/test/unit/test_site.rb +39 -27
  200. data/test/unit/test_storage.rb +9 -6
  201. data/test/unit/test_styles.rb +25 -32
  202. data/test/unit/test_templates.rb +8 -4
  203. metadata +89 -54
  204. data/lib/spontaneous/model/page/request.rb +0 -105
  205. data/lib/spontaneous/storage.rb +0 -22
@@ -28,18 +28,30 @@ describe "Change" do
28
28
  Content.delete_revision(@revision) rescue nil
29
29
  Content.delete_revision(@revision+1) rescue nil
30
30
  Content.delete
31
+ @site.must_publish_all!(false)
31
32
  teardown_site
32
33
  end
33
34
 
35
+ def outstanding_changes
36
+ S::Change.outstanding(@site)
37
+ end
38
+
34
39
  it "flag if the site has never been published" do
35
40
  root = Page.create(:title => "root")
36
41
  5.times { |i| root.things << Page.create(:title => "Page #{i+1}") }
37
- result = S::Change.outstanding
42
+ result = outstanding_changes
38
43
  assert result.key?(:published_revision)
39
44
  result[:published_revision].must_equal 0
40
45
  assert result[:first_publish]
41
46
  end
42
47
 
48
+ it "honors the site must_publish_all? flag" do
49
+ @site.must_publish_all!
50
+ root = Page.create(:title => "root")
51
+ result = outstanding_changes
52
+ result[:must_publish_all].must_equal true
53
+ end
54
+
43
55
 
44
56
  it "list all newly created pages" do
45
57
  root = Page.create(:title => "root")
@@ -48,7 +60,7 @@ describe "Change" do
48
60
 
49
61
  5.times { |i| root.things << Page.create(:title => "Page #{i+1}") }
50
62
 
51
- result = S::Change.outstanding
63
+ result = outstanding_changes
52
64
  result.must_be_instance_of(Hash)
53
65
 
54
66
  pages = result[:changes]
@@ -68,7 +80,7 @@ describe "Change" do
68
80
  root[:first_published_at] = root[:last_published_at] = root.modified_at - 1000
69
81
  root.things << Piece.new
70
82
  root.save.reload
71
- result = S::Change.outstanding[:changes]
83
+ result = outstanding_changes[:changes]
72
84
  result.length.must_equal 1
73
85
  result.first.page.must_equal root
74
86
  end
@@ -83,7 +95,7 @@ describe "Change" do
83
95
 
84
96
  Content.publish(@revision+1, [root.id, root.things.first.id])
85
97
 
86
- result = S::Change.outstanding[:changes]
98
+ result = outstanding_changes[:changes]
87
99
  result.length.must_equal 4
88
100
  Set.new(result.map(&:page_id).flatten).must_equal Set.new(root.things[1..-1].map(&:id))
89
101
  end
@@ -110,7 +122,7 @@ describe "Change" do
110
122
 
111
123
 
112
124
  Content.publish(@revision+1, [root.id])
113
- result = S::Change.outstanding[:changes]
125
+ result = outstanding_changes[:changes]
114
126
 
115
127
  result.length.must_equal 5
116
128
 
@@ -148,7 +160,7 @@ describe "Change" do
148
160
 
149
161
 
150
162
  Content.publish(@revision+1, [root.id])
151
- result = S::Change.outstanding[:changes]
163
+ result = outstanding_changes[:changes]
152
164
 
153
165
  e = nil
154
166
  begin
@@ -174,7 +186,7 @@ describe "Change" do
174
186
  root.save
175
187
 
176
188
  Content.publish(@revision+1, [root.id])
177
- result = S::Change.outstanding[:changes]
189
+ result = outstanding_changes[:changes]
178
190
  change = result.detect { |change| change.page.id == new_child1.id }
179
191
  change.export.must_equal({
180
192
  :id => new_child1.id,
@@ -212,7 +224,7 @@ describe "Change" do
212
224
  root.save
213
225
  last = Time.now + 100
214
226
  ::Content.filter(:id => new_child1.id).update(:modified_at => last)
215
- result = S::Change.outstanding[:changes]
227
+ result = outstanding_changes[:changes]
216
228
  assert result.first.modified_at > result.last.modified_at, "Change list in incorrect order"
217
229
  end
218
230
 
@@ -235,7 +247,7 @@ describe "Change" do
235
247
  page1.slug = "changed"
236
248
  page1.save
237
249
 
238
- result = S::Change.outstanding[:changes]
250
+ result = outstanding_changes[:changes]
239
251
 
240
252
  change = result.detect { |change| change.page.id == page1.id }
241
253
  change.export[:side_effects].must_equal({
@@ -261,7 +273,7 @@ describe "Change" do
261
273
  page1.hide!
262
274
 
263
275
  page1.reload
264
- result = S::Change.outstanding[:changes]
276
+ result = outstanding_changes[:changes]
265
277
  change = result.detect { |change| change.page.id == page1.id }
266
278
  change.export[:side_effects].must_equal({
267
279
  :visibility => [{ :count => 1, :created_at => later.httpdate, :old_value => false, :new_value => true}]
@@ -281,7 +293,7 @@ describe "Change" do
281
293
 
282
294
  lock = Spontaneous::PageLock.create(:page_id => page.id, :content_id => piece.id, :field_id => piece.async.id, :description => "Update Lock")
283
295
  assert page.locked_for_update?
284
- result = S::Change.outstanding[:changes]
296
+ result = outstanding_changes[:changes]
285
297
  change = result.detect { |change| change.page.id == page.id }
286
298
  change.export[:update_locks].must_equal [{
287
299
  id: lock.id,
@@ -330,4 +330,19 @@ describe "Content" do
330
330
  skip "Implement this"
331
331
  end
332
332
  end
333
+
334
+ describe "filtering" do
335
+ before do
336
+ @instances = [P.create, C.create, P.create, C.create]
337
+ end
338
+
339
+ after do
340
+ C.delete
341
+ P.delete
342
+ end
343
+
344
+ it "provides a to_proc method that makes filtering by class easy" do
345
+ @instances.select(&C).map(&:class).must_equal [C, C]
346
+ end
347
+ end
333
348
  end
@@ -0,0 +1,139 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path('../../test_helper', __FILE__)
4
+
5
+ describe "Context" do
6
+ describe "navigation helper" do
7
+ before do
8
+ @site = setup_site
9
+ Page.box :area1
10
+ Page.box :area2
11
+ class ::OtherPage < Page
12
+ box :area3
13
+ box :area4
14
+ end
15
+
16
+ @root = Page.create
17
+ @root.is_root?.must_equal true
18
+ @area1_page1 = Page.create(slug: 'area1_page1')
19
+ @area1_page2 = OtherPage.create(slug: 'area1_page2')
20
+ @root.area1 << @area1_page1
21
+ @root.area1 << @area1_page2
22
+ @area2_page1 = Page.create(slug: 'area2_page1')
23
+ @area2_page2 = OtherPage.create(slug: 'area2_page2')
24
+ @root.area2 << @area2_page1
25
+ @root.area2 << @area2_page2
26
+ @context_class = Class.new do
27
+ include Spontaneous::Output::Context::Navigation
28
+ def initialize(target)
29
+ @target = target
30
+ end
31
+ def __target
32
+ @target
33
+ end
34
+ end
35
+ [@root, @area1_page1, @area1_page2, @area2_page1, @area2_page2].each { |p| p.save.reload }
36
+ end
37
+
38
+ after do
39
+ Content.delete
40
+ teardown_site @site
41
+ Object.send :remove_const, :OtherPage rescue nil
42
+ end
43
+
44
+ it "correctly flags active pages" do
45
+ @target = Page.new
46
+ @area1_page2.area2 << @target
47
+ @target.save.reload
48
+ @context = @context_class.new(@target)
49
+
50
+ result = @context.navigation.map { |p, a| [p.path, a]}
51
+ result.must_equal [["/area1-page1", false], ["/area1-page2", true], ["/area2-page1", false], ["/area2-page2", false]]
52
+ end
53
+
54
+ it "yields the results to a block if given" do
55
+ @target = Page.new
56
+ @area1_page2.area2 << @target
57
+ @target.save.reload
58
+ @context = @context_class.new(@target)
59
+ result = []
60
+ @context.navigation { |p, a| result << [p.path, a]}
61
+ result.must_equal [["/area1-page1", false], ["/area1-page2", true], ["/area2-page1", false], ["/area2-page2", false]]
62
+ end
63
+
64
+ it "doesn't show an active state for root" do
65
+ @context = @context_class.new(@root)
66
+ result = @context.navigation.map { |p, a| [p.path, a]}
67
+ result.must_equal [["/area1-page1", false], ["/area1-page2", false], ["/area2-page1", false], ["/area2-page2", false]]
68
+ end
69
+
70
+ it "shows the section pages as active" do
71
+ @context = @context_class.new(@area1_page2)
72
+ result = @context.navigation.map { |p, a| [p.path, a]}
73
+ result.must_equal [["/area1-page1", false], ["/area1-page2", true], ["/area2-page1", false], ["/area2-page2", false]]
74
+ end
75
+
76
+ it "allows for limiting the navigation to a particular box with :only" do
77
+ @target = Page.new
78
+ @area1_page2.area2 << @target
79
+ @target.save.reload
80
+ @context = @context_class.new(@target)
81
+ result = @context.navigation(only: :area1).map { |p, a| [p.path, a]}
82
+ result.must_equal [["/area1-page1", false], ["/area1-page2", true]]
83
+ end
84
+
85
+ it "allows for limiting the navigation to a particular box with [ :only ]" do
86
+ @target = Page.new
87
+ @area1_page2.area2 << @target
88
+ @target.save.reload
89
+ @context = @context_class.new(@target)
90
+ result = @context.navigation(only: [:area1]).map { |p, a| [p.path, a]}
91
+ result.must_equal [["/area1-page1", false], ["/area1-page2", true]]
92
+ end
93
+
94
+ it "allows for limiting the navigation to a particular box with :box" do
95
+ @target = Page.new
96
+ @area1_page2.area2 << @target
97
+ @target.save.reload
98
+ @context = @context_class.new(@target)
99
+ result = @context.navigation(box: :area1).map { |p, a| [p.path, a]}
100
+ result.must_equal [["/area1-page1", false], ["/area1-page2", true]]
101
+ end
102
+
103
+ it "allows for limiting the navigation to a particular box with :boxes" do
104
+ @target = Page.new
105
+ @area1_page2.area2 << @target
106
+ @target.save.reload
107
+ @context = @context_class.new(@target)
108
+ result = @context.navigation(boxes: [:area1]).map { |p, a| [p.path, a]}
109
+ result.must_equal [["/area1-page1", false], ["/area1-page2", true]]
110
+ end
111
+
112
+ it "allows for limiting the navigation to a particular box" do
113
+ @target = Page.new
114
+ @area1_page2.area2 << @target
115
+ @target.save.reload
116
+ @context = @context_class.new(@target)
117
+ result = @context.navigation(except: :area2).map { |p, a| [p.path, a]}
118
+ result.must_equal [["/area1-page1", false], ["/area1-page2", true]]
119
+ end
120
+
121
+ it "allows for including certain content types" do
122
+ @target = Page.new
123
+ @area1_page2.area2 << @target
124
+ @target.save.reload
125
+ @context = @context_class.new(@target)
126
+ result = @context.navigation(include: :OtherPage).map { |p, a| [p.path, a]}
127
+ result.must_equal [["/area1-page2", true], ["/area2-page2", false]]
128
+ end
129
+
130
+ it "allows for rejecting certain content types" do
131
+ @target = Page.new
132
+ @area1_page2.area2 << @target
133
+ @target.save.reload
134
+ @context = @context_class.new(@target)
135
+ result = @context.navigation(exclude: Page).map { |p, a| [p.path, a]}
136
+ result.must_equal [["/area1-page2", true], ["/area2-page2", false]]
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,374 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path('../../test_helper', __FILE__)
4
+
5
+ ENV['RACK_ENV'] = 'test'
6
+ describe "Controllers" do
7
+ include RackTestMethods
8
+ start do
9
+ @site_root = Dir.mktmpdir
10
+ let(:root) { @site_root }
11
+ S::State.delete
12
+ end
13
+
14
+ finish do
15
+ ::FileUtils.rm_rf(@site_root)
16
+ end
17
+
18
+ class Wrappit
19
+ def initialize(app, options = {})
20
+ @app, @options = app, options
21
+ end
22
+
23
+ def call(env)
24
+ status, headers, body = @app.call(env)
25
+ with = @options[:with]
26
+ wrapped = body.map { |part| [with, part, with].join("") }
27
+ [status, headers, wrapped]
28
+ end
29
+ end
30
+
31
+ before do
32
+ @site = setup_site(root)
33
+
34
+ class ::Page
35
+ controller do
36
+ use Wrappit, with: "*"
37
+ set :something, "else"
38
+ end
39
+ end
40
+
41
+ class ::SubPage < ::Page
42
+ controller do
43
+ get do
44
+ settings.something
45
+ end
46
+ end
47
+
48
+ controller :comments do
49
+ use Wrappit, with: "+"
50
+ get "/" do
51
+ settings.something
52
+ end
53
+ end
54
+ end
55
+
56
+ class ::DeepPage < ::SubPage
57
+ attr_accessor :dynamic_value
58
+ layout do
59
+ "{{ dynamic_value }}"
60
+ end
61
+ controller do
62
+ post {
63
+ page.dynamic_value = params[:value]
64
+ render
65
+ }
66
+ end
67
+ controller :comments do
68
+ post '/' do
69
+ params[:comment]
70
+ end
71
+ end
72
+ end
73
+
74
+ @page = ::SubPage.new(slug: 'something')
75
+ @deep_page = ::DeepPage.new(slug: 'deep')
76
+ end
77
+
78
+ let(:app) { Spontaneous::Rack::Front.application(@site) }
79
+
80
+ after do
81
+ Object.send(:remove_const, :SubPage) rescue nil
82
+ Object.send(:remove_const, :DeepPage) rescue nil
83
+ teardown_site(false)
84
+ end
85
+
86
+ describe "requests" do
87
+ before do
88
+ @site.stubs(:by_path).with('/something').returns(@page)
89
+ @site.stubs(:by_path).with('/deep').returns(@deep_page)
90
+ end
91
+
92
+ it "propagates settings to sub-classes" do
93
+ get '/something'
94
+ last_response.body.must_equal "*else*"
95
+ end
96
+
97
+ it "propagates settings on the base controller to named controllers" do
98
+ get '/something/@comments'
99
+ last_response.body.must_equal "*+else+*"
100
+ end
101
+
102
+ it "allows extension of existing controllers in sub-classes" do
103
+ post '/deep/@comments', comment: "Pungent"
104
+ last_response.body.must_equal "*+Pungent+*"
105
+ end
106
+
107
+ it "can set variables in the resultant render" do
108
+ post '/deep', value: "Present"
109
+ last_response.body.must_equal "*Present*"
110
+ end
111
+
112
+ end
113
+
114
+ it "sets the type as dynamic" do
115
+ SubPage.dynamic?(:get).must_equal true
116
+ SubPage.dynamic?("GET").must_equal true
117
+ @page.dynamic?(:get).must_equal true
118
+ @page.dynamic?("GET").must_equal true
119
+ end
120
+
121
+ describe "PageController" do
122
+ let(:owner) { SubPage.new(uid: "owner") }
123
+ let(:other) { SubPage.new(uid: "other") }
124
+ let(:ctrl) { Spontaneous::Rack::PageController.new!(@site, owner, :html) }
125
+ let(:env) { {Spontaneous::Rack::RENDERER => Spontaneous::Output.published_renderer(@site) } }
126
+
127
+ before do
128
+ ctrl.env = env
129
+ ctrl.request = Rack::Request.new(env)
130
+ ctrl.response = Rack::Response.new
131
+ SubPage.layout { "${uid}:{{success}}" }
132
+ SubPage.add_output :xml
133
+ @site.stubs(:by_uid).with('other').returns(other)
134
+ @site.stubs(:by_uid).with(:other).returns(other)
135
+ end
136
+
137
+ it "allows setting the output format" do
138
+ ctrl.output :xml
139
+ ctrl.render
140
+ ctrl.content_type.must_equal "application/xml;charset=utf-8"
141
+ end
142
+
143
+ it "allows changing the rendered page" do
144
+ ctrl.page(other)
145
+ ctrl.render
146
+ ctrl.body.must_equal "other:"
147
+ end
148
+
149
+ # show allows changing the page, output, status & locals without calling #render
150
+ describe "#show" do
151
+ it "accepts instance, format, status" do
152
+ ctrl.show(other, :xml, 403)
153
+ ctrl.status.must_equal 403
154
+ ctrl.output.must_equal :xml
155
+ ctrl.body.must_equal []
156
+ end
157
+
158
+ it "it sets up params for #render" do
159
+ ctrl.show(other, :xml, 403)
160
+ ctrl.status.must_equal 403
161
+ ctrl.output.must_equal :xml
162
+ ctrl.body.must_equal []
163
+ ctrl.render success: "yes"
164
+ ctrl.body.must_equal "other:yes"
165
+ ctrl.content_type.must_equal "application/xml;charset=utf-8"
166
+ end
167
+
168
+ it "allows render to overwrite the settings" do
169
+ ctrl.show(other, :xml, 403)
170
+ ctrl.render owner, success: "no"
171
+ ctrl.body.must_equal "owner:no"
172
+ ctrl.content_type.must_equal "application/xml;charset=utf-8"
173
+ end
174
+
175
+ it "accepts uid (string), format, status" do
176
+ ctrl.show('other', :xml, 403)
177
+ ctrl.status.must_equal 403
178
+ ctrl.output.must_equal :xml
179
+ ctrl.body.must_equal []
180
+ end
181
+
182
+ it "accepts uid (symbol), format, status" do
183
+ ctrl.show(:other, :xml, 403)
184
+ ctrl.status.must_equal 403
185
+ ctrl.output.must_equal :xml
186
+ ctrl.body.must_equal []
187
+ end
188
+
189
+ it "accepts uid (string), status" do
190
+ ctrl.show('other', 403)
191
+ ctrl.status.must_equal 403
192
+ ctrl.output.must_equal :html
193
+ ctrl.body.must_equal []
194
+ end
195
+
196
+ it "accepts uid (symbol), status" do
197
+ ctrl.show(:other, 403)
198
+ ctrl.status.must_equal 403
199
+ ctrl.output.must_equal :html
200
+ ctrl.body.must_equal []
201
+ end
202
+
203
+ it "accepts uid (string)" do
204
+ ctrl.show('other')
205
+ ctrl.status.must_equal 200
206
+ ctrl.output.must_equal :html
207
+ ctrl.body.must_equal []
208
+ end
209
+
210
+ it "accepts uid (symbol)" do
211
+ ctrl.show(:other)
212
+ ctrl.status.must_equal 200
213
+ ctrl.output.must_equal :html
214
+ ctrl.body.must_equal []
215
+ end
216
+
217
+ it "accepts instance (Content)" do
218
+ ctrl.show(other)
219
+ ctrl.status.must_equal 200
220
+ ctrl.output.must_equal :html
221
+ ctrl.body.must_equal []
222
+ end
223
+
224
+ it "accepts uid (string), status" do
225
+ ctrl.show('other', 409)
226
+ ctrl.status.must_equal 409
227
+ ctrl.output.must_equal :html
228
+ ctrl.body.must_equal []
229
+ end
230
+
231
+ it "accepts uid (symbol), status" do
232
+ ctrl.show(:other, 410)
233
+ ctrl.status.must_equal 410
234
+ ctrl.output.must_equal :html
235
+ ctrl.body.must_equal []
236
+ end
237
+
238
+ it "accepts instance (Content), status" do
239
+ ctrl.show(other, 411)
240
+ ctrl.status.must_equal 411
241
+ ctrl.output.must_equal :html
242
+ ctrl.body.must_equal []
243
+ end
244
+
245
+ it "accepts status" do
246
+ ctrl.show(403)
247
+ ctrl.status.must_equal 403
248
+ ctrl.output.must_equal :html
249
+ ctrl.body.must_equal []
250
+ end
251
+ end
252
+
253
+ describe "#render" do
254
+ it "renders the owning page by default" do
255
+ ctrl.render
256
+ ctrl.status.must_equal 200
257
+ ctrl.output.must_equal :html
258
+ ctrl.body.must_equal "owner:"
259
+ end
260
+
261
+ it "accepts instance, format, status, locals" do
262
+ ctrl.render(other, :xml, 403, success: "yes")
263
+ ctrl.status.must_equal 403
264
+ ctrl.output.must_equal :xml
265
+ ctrl.body.must_equal "other:yes"
266
+ end
267
+
268
+ it "accepts uid (string), format, status, locals" do
269
+ ctrl.render('other', :xml, 403, success: "yes")
270
+ ctrl.status.must_equal 403
271
+ ctrl.output.must_equal :xml
272
+ ctrl.body.must_equal "other:yes"
273
+ end
274
+
275
+ it "accepts uid (symbol), format, status, locals" do
276
+ ctrl.render(:other, :xml, 403, success: "yes")
277
+ ctrl.status.must_equal 403
278
+ ctrl.output.must_equal :xml
279
+ ctrl.body.must_equal "other:yes"
280
+ end
281
+
282
+ it "accepts uid (string), status, locals" do
283
+ ctrl.render('other', 403, success: "yes")
284
+ ctrl.status.must_equal 403
285
+ ctrl.output.must_equal :html
286
+ ctrl.body.must_equal "other:yes"
287
+ end
288
+
289
+ it "accepts uid (symbol), status, locals" do
290
+ ctrl.render(:other, 403, success: "yes")
291
+ ctrl.status.must_equal 403
292
+ ctrl.output.must_equal :html
293
+ ctrl.body.must_equal "other:yes"
294
+ end
295
+
296
+ it "accepts uid (string)" do
297
+ ctrl.render('other')
298
+ ctrl.status.must_equal 200
299
+ ctrl.output.must_equal :html
300
+ ctrl.body.must_equal "other:"
301
+ end
302
+
303
+ it "accepts uid (symbol)" do
304
+ ctrl.render(:other)
305
+ ctrl.status.must_equal 200
306
+ ctrl.output.must_equal :html
307
+ ctrl.body.must_equal "other:"
308
+ end
309
+
310
+ it "accepts instance (Content)" do
311
+ ctrl.render(other)
312
+ ctrl.status.must_equal 200
313
+ ctrl.output.must_equal :html
314
+ ctrl.body.must_equal "other:"
315
+ end
316
+
317
+ it "accepts uid (string), status" do
318
+ ctrl.render('other', 409)
319
+ ctrl.status.must_equal 409
320
+ ctrl.output.must_equal :html
321
+ ctrl.body.must_equal "other:"
322
+ end
323
+
324
+ it "accepts uid (symbol), status" do
325
+ ctrl.render(:other, 410)
326
+ ctrl.status.must_equal 410
327
+ ctrl.output.must_equal :html
328
+ ctrl.body.must_equal "other:"
329
+ end
330
+
331
+ it "accepts instance (Content), status" do
332
+ ctrl.render(other, 411)
333
+ ctrl.status.must_equal 411
334
+ ctrl.output.must_equal :html
335
+ ctrl.body.must_equal "other:"
336
+ end
337
+
338
+ it "accepts locals" do
339
+ ctrl.render(success: "yes")
340
+ ctrl.status.must_equal 200
341
+ ctrl.output.must_equal :html
342
+ ctrl.body.must_equal "owner:yes"
343
+ end
344
+
345
+ it "accepts uid (string), locals" do
346
+ ctrl.render('$other', success: "yes")
347
+ ctrl.status.must_equal 200
348
+ ctrl.output.must_equal :html
349
+ ctrl.body.must_equal "other:yes"
350
+ end
351
+
352
+ it "accepts uid (symbol), locals" do
353
+ ctrl.render(:other, success: "yes")
354
+ ctrl.status.must_equal 200
355
+ ctrl.output.must_equal :html
356
+ ctrl.body.must_equal "other:yes"
357
+ end
358
+
359
+ it "accepts status" do
360
+ ctrl.render(403)
361
+ ctrl.status.must_equal 403
362
+ ctrl.output.must_equal :html
363
+ ctrl.body.must_equal "owner:"
364
+ end
365
+
366
+ it "accepts status, locals" do
367
+ ctrl.render(403, success: "no")
368
+ ctrl.status.must_equal 403
369
+ ctrl.output.must_equal :html
370
+ ctrl.body.must_equal "owner:no"
371
+ end
372
+ end
373
+ end
374
+ end