spontaneous 0.2.0.beta5 → 0.2.0.beta6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (227) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +39 -0
  4. data/Gemfile +2 -0
  5. data/Readme.markdown +4 -4
  6. data/application/css/core.css.scss +144 -43
  7. data/application/css/definitions.css.scss +50 -16
  8. data/application/css/dialogue.css.scss +5 -2
  9. data/application/css/editing.css.scss +7 -7
  10. data/application/css/font.css.scss +1 -1
  11. data/application/css/meta.css.scss +6 -6
  12. data/application/css/popover.css.scss +6 -6
  13. data/application/css/top.css.scss +8 -1
  14. data/application/js/add_alias_dialogue.js +137 -36
  15. data/application/js/add_home_dialogue.js +10 -10
  16. data/application/js/ajax.js +26 -26
  17. data/application/js/authentication.js +2 -2
  18. data/application/js/box.js +21 -10
  19. data/application/js/box_container.js +13 -7
  20. data/application/js/compatibility.js +19 -17
  21. data/application/js/conflicted_field_dialogue.js +5 -5
  22. data/application/js/content.js +22 -16
  23. data/application/js/content_area.js +62 -33
  24. data/application/js/dialogue.js +16 -16
  25. data/application/js/dom.js +9 -10
  26. data/application/js/edit_panel.js +25 -20
  27. data/application/js/editing.js +21 -8
  28. data/application/js/entry.js +1 -1
  29. data/application/js/extensions.js +11 -11
  30. data/application/js/field/boolean.js +6 -6
  31. data/application/js/field/date.js +1 -1
  32. data/application/js/field/file.js +17 -17
  33. data/application/js/field/image.js +27 -27
  34. data/application/js/field/markdown.js +72 -71
  35. data/application/js/field/select.js +9 -9
  36. data/application/js/field/string.js +3 -3
  37. data/application/js/field/webvideo.js +2 -2
  38. data/application/js/field_preview.js +3 -0
  39. data/application/js/init.js +3 -2
  40. data/application/js/jquery-selection-position.js +13 -13
  41. data/application/js/location.js +17 -12
  42. data/application/js/login.js +2 -2
  43. data/application/js/meta_view/user_admin.js +101 -101
  44. data/application/js/metadata.js +1 -1
  45. data/application/js/page.js +2 -2
  46. data/application/js/page_browser.js +13 -13
  47. data/application/js/page_entry.js +1 -1
  48. data/application/js/panel/root_menu.js +10 -10
  49. data/application/js/popover.js +6 -5
  50. data/application/js/popover_view.js +5 -5
  51. data/application/js/preview.js +10 -4
  52. data/application/js/progress.js +6 -6
  53. data/application/js/properties.js +35 -6
  54. data/application/js/publish.js +43 -43
  55. data/application/js/require.js +14 -14
  56. data/application/js/services.js +3 -3
  57. data/application/js/sharded_upload.js +9 -8
  58. data/application/js/side_bar.js +5 -5
  59. data/application/js/state.js +2 -2
  60. data/application/js/status_bar.js +6 -6
  61. data/application/js/top_bar.js +97 -65
  62. data/application/js/types.js +9 -6
  63. data/application/js/upload.js +4 -4
  64. data/application/js/upload_manager.js +21 -21
  65. data/application/js/user.js +1 -1
  66. data/application/js/vendor/jquery.velocity.min.js +7 -0
  67. data/application/js/views.js +32 -8
  68. data/application/js/views/box_view.js +51 -31
  69. data/application/js/views/page_piece_view.js +17 -15
  70. data/application/js/views/page_view.js +54 -43
  71. data/application/js/views/piece_view.js +44 -37
  72. data/application/static/font/fontawesome-webfont-4f0022f25672c7f501c339cbf98d9117.ttf +0 -0
  73. data/application/views/index.erb +1 -0
  74. data/db/migrations/20130114120000_create_revision_tables.rb +2 -1
  75. data/db/migrations/20130813111009_increase_path_length.rb +11 -2
  76. data/db/migrations/20140506171823_add_index_to_target_id.rb +11 -0
  77. data/db/migrations/20140514090204_add_content_hash.rb +59 -0
  78. data/db/migrations/20140519150253_add_content_hash_timestamp.rb +20 -0
  79. data/lib/spontaneous.rb +0 -1
  80. data/lib/spontaneous/asset/environment.rb +77 -15
  81. data/lib/spontaneous/box.rb +21 -0
  82. data/lib/spontaneous/capistrano/deploy.rb +1 -1
  83. data/lib/spontaneous/capistrano/sync.rb +8 -7
  84. data/lib/spontaneous/change.rb +4 -2
  85. data/lib/spontaneous/cli/fields.rb +7 -3
  86. data/lib/spontaneous/cli/generate.rb +2 -0
  87. data/lib/spontaneous/cli/init.rb +24 -93
  88. data/lib/spontaneous/cli/init/db.rb +94 -0
  89. data/lib/spontaneous/cli/init/mysql.rb +17 -0
  90. data/lib/spontaneous/cli/init/postgresql.rb +33 -0
  91. data/lib/spontaneous/cli/init/sqlite.rb +14 -0
  92. data/lib/spontaneous/cli/site.rb +45 -20
  93. data/lib/spontaneous/collections/box_set.rb +3 -0
  94. data/lib/spontaneous/collections/entry_set.rb +43 -4
  95. data/lib/spontaneous/collections/field_set.rb +14 -2
  96. data/lib/spontaneous/data_mapper.rb +40 -7
  97. data/lib/spontaneous/data_mapper/content_model.rb +1 -1
  98. data/lib/spontaneous/data_mapper/content_model/associations.rb +63 -12
  99. data/lib/spontaneous/data_mapper/content_model/timestamps.rb +9 -14
  100. data/lib/spontaneous/data_mapper/content_table.rb +4 -2
  101. data/lib/spontaneous/data_mapper/dataset.rb +31 -2
  102. data/lib/spontaneous/data_mapper/scope.rb +37 -20
  103. data/lib/spontaneous/errors.rb +6 -0
  104. data/lib/spontaneous/facet.rb +20 -10
  105. data/lib/spontaneous/field/base.rb +8 -1
  106. data/lib/spontaneous/field/file.rb +28 -3
  107. data/lib/spontaneous/field/image.rb +2 -0
  108. data/lib/spontaneous/field/update.rb +6 -0
  109. data/lib/spontaneous/field/webvideo/vimeo.rb +6 -1
  110. data/lib/spontaneous/field/webvideo/vine.rb +1 -1
  111. data/lib/spontaneous/field/webvideo/youtube.rb +1 -1
  112. data/lib/spontaneous/generators/site.rb +6 -4
  113. data/lib/spontaneous/generators/site/.gitignore +1 -0
  114. data/lib/spontaneous/generators/site/Gemfile.tt +3 -3
  115. data/lib/spontaneous/generators/site/config/{indexes.rb.tt → initializers/indexes.rb.tt} +0 -0
  116. data/lib/spontaneous/generators/site/config/initializers/publishing.rb.tt +78 -0
  117. data/lib/spontaneous/generators/site/{config/database.yml.tt → db/mysql2.yml.tt} +7 -6
  118. data/lib/spontaneous/generators/site/db/postgres.yml.tt +25 -0
  119. data/lib/spontaneous/generators/site/db/sqlite3.yml.tt +18 -0
  120. data/lib/spontaneous/generators/site/public/humans.txt.tt +14 -0
  121. data/lib/spontaneous/generators/site/templates/layouts/standard.html.cut.tt +51 -0
  122. data/lib/spontaneous/loader.rb +1 -1
  123. data/lib/spontaneous/logger.rb +1 -1
  124. data/lib/spontaneous/media/image/optimizer.rb +1 -1
  125. data/lib/spontaneous/media/image/processor.rb +11 -2
  126. data/lib/spontaneous/media/image/renderable.rb +2 -0
  127. data/lib/spontaneous/model.rb +3 -0
  128. data/lib/spontaneous/model/box/allowed_types.rb +17 -4
  129. data/lib/spontaneous/model/core.rb +36 -3
  130. data/lib/spontaneous/model/core/aliases.rb +5 -2
  131. data/lib/spontaneous/model/core/boxes.rb +6 -0
  132. data/lib/spontaneous/model/core/cascading_change.rb +38 -0
  133. data/lib/spontaneous/model/core/content_hash.rb +171 -0
  134. data/lib/spontaneous/model/core/entries.rb +0 -19
  135. data/lib/spontaneous/model/core/fields.rb +11 -0
  136. data/lib/spontaneous/model/core/modifications.rb +22 -21
  137. data/lib/spontaneous/model/core/render.rb +3 -0
  138. data/lib/spontaneous/model/core/serialisation.rb +18 -17
  139. data/lib/spontaneous/model/page.rb +35 -8
  140. data/lib/spontaneous/model/page/page_tree.rb +20 -8
  141. data/lib/spontaneous/model/page/paths.rb +79 -50
  142. data/lib/spontaneous/model/page/singleton.rb +71 -0
  143. data/lib/spontaneous/model/page/site_map.rb +2 -1
  144. data/lib/spontaneous/model/page/site_timestamps.rb +2 -2
  145. data/lib/spontaneous/model/piece.rb +10 -0
  146. data/lib/spontaneous/output/context.rb +13 -6
  147. data/lib/spontaneous/output/format.rb +30 -5
  148. data/lib/spontaneous/output/helpers/script_helper.rb +8 -0
  149. data/lib/spontaneous/output/helpers/stylesheet_helper.rb +7 -0
  150. data/lib/spontaneous/output/renderable.rb +16 -0
  151. data/lib/spontaneous/output/store.rb +1 -1
  152. data/lib/spontaneous/output/template/renderer.rb +2 -2
  153. data/lib/spontaneous/page_piece.rb +25 -1
  154. data/lib/spontaneous/prototypes/box_prototype.rb +13 -0
  155. data/lib/spontaneous/prototypes/field_prototype.rb +7 -4
  156. data/lib/spontaneous/publishing.rb +10 -5
  157. data/lib/spontaneous/publishing/immediate.rb +32 -349
  158. data/lib/spontaneous/publishing/pipeline.rb +43 -0
  159. data/lib/spontaneous/publishing/progress.rb +186 -0
  160. data/lib/spontaneous/publishing/publish.rb +107 -0
  161. data/lib/spontaneous/publishing/rerender.rb +17 -0
  162. data/lib/spontaneous/publishing/revision.rb +53 -18
  163. data/lib/spontaneous/publishing/simultaneous.rb +1 -1
  164. data/lib/spontaneous/publishing/steps.rb +154 -0
  165. data/lib/spontaneous/publishing/steps/activate_revision.rb +45 -0
  166. data/lib/spontaneous/publishing/steps/archive_old_revisions.rb +22 -0
  167. data/lib/spontaneous/publishing/steps/base_step.rb +49 -0
  168. data/lib/spontaneous/publishing/steps/copy_static_files.rb +74 -0
  169. data/lib/spontaneous/publishing/steps/create_revision_directory.rb +24 -0
  170. data/lib/spontaneous/publishing/steps/generate_rackup_file.rb +51 -0
  171. data/lib/spontaneous/publishing/steps/generate_search_indexes.rb +24 -0
  172. data/lib/spontaneous/publishing/steps/render_revision.rb +69 -0
  173. data/lib/spontaneous/publishing/steps/write_revision_file.rb +43 -0
  174. data/lib/spontaneous/rack/back.rb +3 -1
  175. data/lib/spontaneous/rack/back/alias.rb +9 -8
  176. data/lib/spontaneous/rack/front.rb +1 -1
  177. data/lib/spontaneous/rack/middleware.rb +7 -4
  178. data/lib/spontaneous/rack/middleware/transaction.rb +14 -0
  179. data/lib/spontaneous/rack/page_controller.rb +23 -8
  180. data/lib/spontaneous/revision.rb +5 -10
  181. data/lib/spontaneous/schema.rb +5 -0
  182. data/lib/spontaneous/server.rb +3 -1
  183. data/lib/spontaneous/site.rb +17 -10
  184. data/lib/spontaneous/site/publishing.rb +25 -3
  185. data/lib/spontaneous/site/state.rb +7 -3
  186. data/lib/spontaneous/tasks/database.rake +5 -10
  187. data/lib/spontaneous/utils/database/mysql_dumper.rb +5 -1
  188. data/lib/spontaneous/version.rb +1 -1
  189. data/spontaneous.gemspec +4 -3
  190. data/test/fixtures/example_application/config/initializers/initializer1.rb +1 -0
  191. data/test/fixtures/example_application/config/initializers/initializer2.rb +1 -0
  192. data/test/fixtures/example_application/config/initializers/publishing.rb +13 -0
  193. data/test/fixtures/search/config/{indexes.rb → initializers/indexes.rb} +0 -0
  194. data/test/fixtures/serialisation/root_hash.yaml.erb +10 -4
  195. data/test/functional/test_application.rb +10 -0
  196. data/test/functional/test_back.rb +23 -5
  197. data/test/functional/test_cli.rb +98 -34
  198. data/test/functional/test_front.rb +7 -3
  199. data/test/test_helper.rb +35 -28
  200. data/test/unit/test_alias.rb +20 -3
  201. data/test/unit/test_assets.rb +58 -30
  202. data/test/unit/test_changesets.rb +20 -12
  203. data/test/unit/test_content_hash.rb +496 -0
  204. data/test/unit/test_context.rb +28 -1
  205. data/test/unit/test_controllers.rb +96 -61
  206. data/test/unit/test_crypt.rb +1 -8
  207. data/test/unit/test_datamapper.rb +95 -19
  208. data/test/unit/test_features.rb +1 -4
  209. data/test/unit/test_fields.rb +61 -12
  210. data/test/unit/test_generators.rb +39 -2
  211. data/test/unit/test_images.rb +3 -1
  212. data/test/unit/test_modifications.rb +224 -219
  213. data/test/unit/test_output_store.rb +10 -0
  214. data/test/unit/{test_formats.rb → test_outputs.rb} +75 -6
  215. data/test/unit/test_page.rb +61 -15
  216. data/test/unit/test_plugins.rb +2 -42
  217. data/test/unit/test_publishing_pipeline.rb +1050 -0
  218. data/test/unit/test_render.rb +30 -0
  219. data/test/unit/test_revisions.rb +110 -2
  220. data/test/unit/test_schema.rb +4 -0
  221. data/test/unit/test_search.rb +1 -1
  222. data/test/unit/test_serialisation.rb +6 -1
  223. data/test/unit/test_singletons.rb +159 -0
  224. data/test/unit/test_site.rb +71 -44
  225. metadata +140 -86
  226. data/application/static/font/fontawesome-webfont-1c66a4738b40ef0f6b1abca0ba9a796d.ttf +0 -0
  227. data/test/unit/test_publishing.rb +0 -330
@@ -109,7 +109,7 @@ describe "Context" do
109
109
  result.must_equal [["/area1-page1", false], ["/area1-page2", true]]
110
110
  end
111
111
 
112
- it "allows for limiting the navigation to a particular box" do
112
+ it "allows for excluding a particular box" do
113
113
  @target = Page.new
114
114
  @area1_page2.area2 << @target
115
115
  @target.save.reload
@@ -135,5 +135,32 @@ describe "Context" do
135
135
  result = @context.navigation(exclude: Page).map { |p, a| [p.path, a]}
136
136
  result.must_equal [["/area1-page2", true], ["/area2-page2", false]]
137
137
  end
138
+
139
+ it "shows children of the public root when rendering a private root" do
140
+ @target = Page.create_root "error"
141
+ @context = @context_class.new(@target)
142
+ result = @context.navigation.map { |p, a| [p.path, a]}
143
+ result.must_equal [["/area1-page1", false], ["/area1-page2", false], ["/area2-page1", false], ["/area2-page2", false]]
144
+ end
145
+
146
+ it "shows children of the public root when rendering a private page" do
147
+ root = Page.create_root "error"
148
+ @target = Page.new
149
+ root.area2 << @target
150
+ @target.save.reload
151
+ @context = @context_class.new(@target)
152
+ result = @context.navigation.map { |p, a| [p.path, a]}
153
+ result.must_equal [["/area1-page1", false], ["/area1-page2", false], ["/area2-page1", false], ["/area2-page2", false]]
154
+ end
155
+
156
+ it "doesn't throw errors when attempting to render from a non-existant parent" do
157
+ root = Page.create_root "error"
158
+ @target = Page.new
159
+ root.area2 << @target
160
+ @target.save.reload
161
+ @context = @context_class.new(@target)
162
+ result = @context.navigation(depth: 2).map { |p, a| [p.path, a]}
163
+ result.must_equal []
164
+ end
138
165
  end
139
166
  end
@@ -119,19 +119,33 @@ describe "Controllers" do
119
119
  end
120
120
 
121
121
  describe "PageController" do
122
- let(:owner) { SubPage.new(uid: "owner") }
123
- let(:other) { SubPage.new(uid: "other") }
122
+ let(:owner) { OwnerPage.create(uid: "the_owner") }
123
+ let(:other) { OtherPage.create(uid: "the_other") }
124
124
  let(:ctrl) { Spontaneous::Rack::PageController.new!(@site, owner, :html) }
125
125
  let(:env) { {Spontaneous::Rack::RENDERER => Spontaneous::Output.published_renderer(@site) } }
126
126
 
127
127
  before do
128
+ class ::OwnerPage < SubPage
129
+ singleton :owner
130
+ end
131
+ class ::OtherPage < SubPage
132
+ singleton :other
133
+ end
128
134
  ctrl.env = env
129
135
  ctrl.request = Rack::Request.new(env)
130
136
  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)
137
+ [OwnerPage, OtherPage].each do |type|
138
+ type.layout { "${uid}:{{success}}" }
139
+ type.add_output :xml
140
+ end
141
+ @site.stubs(:other).returns(other)
142
+ end
143
+
144
+ after do
145
+ owner.destroy
146
+ other.destroy
147
+ Object.send :remove_const, :OwnerPage rescue nil
148
+ Object.send :remove_const, :OtherPage rescue nil
135
149
  end
136
150
 
137
151
  it "allows setting the output format" do
@@ -143,7 +157,7 @@ describe "Controllers" do
143
157
  it "allows changing the rendered page" do
144
158
  ctrl.page(other)
145
159
  ctrl.render
146
- ctrl.body.must_equal "other:"
160
+ ctrl.body.must_equal "the_other:"
147
161
  end
148
162
 
149
163
  # show allows changing the page, output, status & locals without calling #render
@@ -161,76 +175,76 @@ describe "Controllers" do
161
175
  ctrl.output.must_equal :xml
162
176
  ctrl.body.must_equal []
163
177
  ctrl.render success: "yes"
164
- ctrl.body.must_equal "other:yes"
178
+ ctrl.body.must_equal "the_other:yes"
165
179
  ctrl.content_type.must_equal "application/xml;charset=utf-8"
166
180
  end
167
181
 
168
182
  it "allows render to overwrite the settings" do
169
183
  ctrl.show(other, :xml, 403)
170
184
  ctrl.render owner, success: "no"
171
- ctrl.body.must_equal "owner:no"
185
+ ctrl.body.must_equal "the_owner:no"
172
186
  ctrl.content_type.must_equal "application/xml;charset=utf-8"
173
187
  end
174
188
 
175
- it "accepts uid (string), format, status" do
189
+ it "accepts singleton name (symbol), format, status" do
176
190
  ctrl.show('other', :xml, 403)
177
191
  ctrl.status.must_equal 403
178
192
  ctrl.output.must_equal :xml
179
193
  ctrl.body.must_equal []
180
194
  end
181
195
 
182
- it "accepts uid (symbol), format, status" do
183
- ctrl.show(:other, :xml, 403)
196
+ it "accepts singleton class, format, status" do
197
+ ctrl.show(OtherPage, :xml, 403)
184
198
  ctrl.status.must_equal 403
185
199
  ctrl.output.must_equal :xml
186
200
  ctrl.body.must_equal []
187
201
  end
188
202
 
189
- it "accepts uid (string), status" do
203
+ it "accepts singleton name (string), status" do
190
204
  ctrl.show('other', 403)
191
205
  ctrl.status.must_equal 403
192
206
  ctrl.output.must_equal :html
193
207
  ctrl.body.must_equal []
194
208
  end
195
209
 
196
- it "accepts uid (symbol), status" do
210
+ it "accepts singleton name (symbol), status" do
197
211
  ctrl.show(:other, 403)
198
212
  ctrl.status.must_equal 403
199
213
  ctrl.output.must_equal :html
200
214
  ctrl.body.must_equal []
201
215
  end
202
216
 
203
- it "accepts uid (string)" do
204
- ctrl.show('other')
205
- ctrl.status.must_equal 200
217
+ it "accepts singleton class, status" do
218
+ ctrl.show(OtherPage, 410)
219
+ ctrl.status.must_equal 410
206
220
  ctrl.output.must_equal :html
207
221
  ctrl.body.must_equal []
208
222
  end
209
223
 
210
- it "accepts uid (symbol)" do
211
- ctrl.show(:other)
224
+ it "accepts singleton name" do
225
+ ctrl.show('other')
212
226
  ctrl.status.must_equal 200
213
227
  ctrl.output.must_equal :html
214
228
  ctrl.body.must_equal []
215
229
  end
216
230
 
217
- it "accepts instance (Content)" do
218
- ctrl.show(other)
231
+ it "accepts singleton name" do
232
+ ctrl.show(:other)
219
233
  ctrl.status.must_equal 200
220
234
  ctrl.output.must_equal :html
221
235
  ctrl.body.must_equal []
222
236
  end
223
237
 
224
- it "accepts uid (string), status" do
225
- ctrl.show('other', 409)
226
- ctrl.status.must_equal 409
238
+ it "accepts singleton class" do
239
+ ctrl.show(OtherPage)
240
+ ctrl.status.must_equal 200
227
241
  ctrl.output.must_equal :html
228
242
  ctrl.body.must_equal []
229
243
  end
230
244
 
231
- it "accepts uid (symbol), status" do
232
- ctrl.show(:other, 410)
233
- ctrl.status.must_equal 410
245
+ it "accepts instance (Content)" do
246
+ ctrl.show(other)
247
+ ctrl.status.must_equal 200
234
248
  ctrl.output.must_equal :html
235
249
  ctrl.body.must_equal []
236
250
  end
@@ -255,119 +269,140 @@ describe "Controllers" do
255
269
  ctrl.render
256
270
  ctrl.status.must_equal 200
257
271
  ctrl.output.must_equal :html
258
- ctrl.body.must_equal "owner:"
272
+ ctrl.body.must_equal "the_owner:"
259
273
  end
260
274
 
261
275
  it "accepts instance, format, status, locals" do
262
276
  ctrl.render(other, :xml, 403, success: "yes")
263
277
  ctrl.status.must_equal 403
264
278
  ctrl.output.must_equal :xml
265
- ctrl.body.must_equal "other:yes"
279
+ ctrl.body.must_equal "the_other:yes"
266
280
  end
267
281
 
268
- it "accepts uid (string), format, status, locals" do
282
+ it "accepts singleton name (string), format, status, locals" do
269
283
  ctrl.render('other', :xml, 403, success: "yes")
270
284
  ctrl.status.must_equal 403
271
285
  ctrl.output.must_equal :xml
272
- ctrl.body.must_equal "other:yes"
286
+ ctrl.body.must_equal "the_other:yes"
273
287
  end
274
288
 
275
- it "accepts uid (symbol), format, status, locals" do
289
+ it "accepts singleton name (symbol), format, status, locals" do
276
290
  ctrl.render(:other, :xml, 403, success: "yes")
277
291
  ctrl.status.must_equal 403
278
292
  ctrl.output.must_equal :xml
279
- ctrl.body.must_equal "other:yes"
293
+ ctrl.body.must_equal "the_other:yes"
280
294
  end
281
295
 
282
- it "accepts uid (string), status, locals" do
296
+ it "accepts singleton class, format, status, locals" do
297
+ ctrl.render(OtherPage, :xml, 403, success: "yes")
298
+ ctrl.status.must_equal 403
299
+ ctrl.output.must_equal :xml
300
+ ctrl.body.must_equal "the_other:yes"
301
+ end
302
+
303
+ it "accepts singleton name (string), status, locals" do
283
304
  ctrl.render('other', 403, success: "yes")
284
305
  ctrl.status.must_equal 403
285
306
  ctrl.output.must_equal :html
286
- ctrl.body.must_equal "other:yes"
307
+ ctrl.body.must_equal "the_other:yes"
287
308
  end
288
309
 
289
- it "accepts uid (symbol), status, locals" do
310
+ it "accepts singleton name (symbol), status, locals" do
290
311
  ctrl.render(:other, 403, success: "yes")
291
312
  ctrl.status.must_equal 403
292
313
  ctrl.output.must_equal :html
293
- ctrl.body.must_equal "other:yes"
314
+ ctrl.body.must_equal "the_other:yes"
315
+ end
316
+
317
+ it "accepts singleton class, status, locals" do
318
+ ctrl.render(OtherPage, 403, success: "yes")
319
+ ctrl.status.must_equal 403
320
+ ctrl.output.must_equal :html
321
+ ctrl.body.must_equal "the_other:yes"
294
322
  end
295
323
 
296
- it "accepts uid (string)" do
324
+ it "accepts singleton name (string)" do
297
325
  ctrl.render('other')
298
326
  ctrl.status.must_equal 200
299
327
  ctrl.output.must_equal :html
300
- ctrl.body.must_equal "other:"
328
+ ctrl.body.must_equal "the_other:"
301
329
  end
302
330
 
303
- it "accepts uid (symbol)" do
331
+ it "accepts singleton name (symbol)" do
304
332
  ctrl.render(:other)
305
333
  ctrl.status.must_equal 200
306
334
  ctrl.output.must_equal :html
307
- ctrl.body.must_equal "other:"
335
+ ctrl.body.must_equal "the_other:"
308
336
  end
309
337
 
310
- it "accepts instance (Content)" do
311
- ctrl.render(other)
338
+ it "accepts singleton class" do
339
+ ctrl.render(OtherPage)
312
340
  ctrl.status.must_equal 200
313
341
  ctrl.output.must_equal :html
314
- ctrl.body.must_equal "other:"
342
+ ctrl.body.must_equal "the_other:"
315
343
  end
316
344
 
317
- it "accepts uid (string), status" do
345
+ it "accepts singleton name (string), status" do
318
346
  ctrl.render('other', 409)
319
347
  ctrl.status.must_equal 409
320
348
  ctrl.output.must_equal :html
321
- ctrl.body.must_equal "other:"
349
+ ctrl.body.must_equal "the_other:"
322
350
  end
323
351
 
324
- it "accepts uid (symbol), status" do
352
+ it "accepts singleton name (symbol), status" do
325
353
  ctrl.render(:other, 410)
326
354
  ctrl.status.must_equal 410
327
355
  ctrl.output.must_equal :html
328
- ctrl.body.must_equal "other:"
356
+ ctrl.body.must_equal "the_other:"
357
+ end
358
+
359
+ it "accepts singleton class, status" do
360
+ ctrl.render(OtherPage, 410)
361
+ ctrl.status.must_equal 410
362
+ ctrl.output.must_equal :html
363
+ ctrl.body.must_equal "the_other:"
364
+ end
365
+
366
+ it "accepts instance (Content)" do
367
+ ctrl.render(other)
368
+ ctrl.status.must_equal 200
369
+ ctrl.output.must_equal :html
370
+ ctrl.body.must_equal "the_other:"
329
371
  end
330
372
 
331
373
  it "accepts instance (Content), status" do
332
374
  ctrl.render(other, 411)
333
375
  ctrl.status.must_equal 411
334
376
  ctrl.output.must_equal :html
335
- ctrl.body.must_equal "other:"
377
+ ctrl.body.must_equal "the_other:"
336
378
  end
337
379
 
338
380
  it "accepts locals" do
339
381
  ctrl.render(success: "yes")
340
382
  ctrl.status.must_equal 200
341
383
  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"
384
+ ctrl.body.must_equal "the_owner:yes"
350
385
  end
351
386
 
352
- it "accepts uid (symbol), locals" do
387
+ it "accepts singleton name (symbol), locals" do
353
388
  ctrl.render(:other, success: "yes")
354
389
  ctrl.status.must_equal 200
355
390
  ctrl.output.must_equal :html
356
- ctrl.body.must_equal "other:yes"
391
+ ctrl.body.must_equal "the_other:yes"
357
392
  end
358
393
 
359
394
  it "accepts status" do
360
395
  ctrl.render(403)
361
396
  ctrl.status.must_equal 403
362
397
  ctrl.output.must_equal :html
363
- ctrl.body.must_equal "owner:"
398
+ ctrl.body.must_equal "the_owner:"
364
399
  end
365
400
 
366
401
  it "accepts status, locals" do
367
402
  ctrl.render(403, success: "no")
368
403
  ctrl.status.must_equal 403
369
404
  ctrl.output.must_equal :html
370
- ctrl.body.must_equal "owner:no"
405
+ ctrl.body.must_equal "the_owner:no"
371
406
  end
372
407
  end
373
408
  end
@@ -99,15 +99,8 @@ describe "Crypt" do
99
99
  version, _ = Crypt.version_split(hash)
100
100
  version.must_equal Crypt.current.version
101
101
  end
102
-
103
- it "take at least half a second to compute" do
104
- hash = nil
105
- bm = Benchmark.measure { hash = Crypt::hash_password(@password) }
106
- bm.real.must_be :>=, 0.5
107
- bm = Benchmark.measure { Crypt::valid?(@password, hash) }
108
- bm.real.must_be :>=, 0.5
109
- end
110
102
  end
103
+
111
104
  describe "users" do
112
105
  before do
113
106
  S::Permissions::User.delete
@@ -158,6 +158,15 @@ describe "DataMapper" do
158
158
  end
159
159
  end
160
160
 
161
+ it "knows if the scope is editable" do
162
+ @mapper.revision(10) do
163
+ @mapper.editable?.must_equal false
164
+ end
165
+ @mapper.editable do
166
+ @mapper.editable?.must_equal true
167
+ end
168
+ end
169
+
161
170
  it "allow for retrieval of rows from a specific revision" do
162
171
  @database.fetch = { id:1, label:"column1", type_sid:"MockContent2" }
163
172
  instance = @mapper.revision(20).get(1)
@@ -347,9 +356,9 @@ describe "DataMapper" do
347
356
  end
348
357
  end
349
358
  @database.sqls.must_equal [
350
- "SELECT * FROM content WHERE ((type_sid IN ('MockContent2', 'MockContent3')) AND (hidden IS FALSE) AND (id = 1)) LIMIT 1",
359
+ "SELECT * FROM content WHERE ((hidden IS FALSE) AND (type_sid IN ('MockContent2', 'MockContent3')) AND (id = 1)) LIMIT 1",
351
360
  "SELECT * FROM content WHERE ((type_sid IN ('MockContent2', 'MockContent3')) AND (id = 1)) LIMIT 1",
352
- "SELECT * FROM content WHERE ((type_sid IN ('MockContent2', 'MockContent3')) AND (hidden IS FALSE) AND (id = 1)) LIMIT 1",
361
+ "SELECT * FROM content WHERE ((hidden IS FALSE) AND (type_sid IN ('MockContent2', 'MockContent3')) AND (id = 1)) LIMIT 1",
353
362
  ]
354
363
  end
355
364
 
@@ -361,7 +370,7 @@ describe "DataMapper" do
361
370
  end
362
371
  end
363
372
  @database.sqls.must_equal [
364
- "SELECT * FROM __r00025_content WHERE ((type_sid IN ('MockContent2', 'MockContent3')) AND (hidden IS FALSE) AND (id = 1)) LIMIT 1",
373
+ "SELECT * FROM __r00025_content WHERE ((hidden IS FALSE) AND (type_sid IN ('MockContent2', 'MockContent3')) AND (id = 1)) LIMIT 1",
365
374
  ]
366
375
  end
367
376
 
@@ -397,6 +406,29 @@ describe "DataMapper" do
397
406
  end
398
407
  end
399
408
 
409
+ describe "prepared statements" do
410
+ it "allows for defining the same prepared statements in multiple scopes" do
411
+ sqls = []
412
+ ps0 = @mapper.prepare(:select, :something) { @mapper.filter(MockContent2, label: :$label) }
413
+ @mapper.visible do
414
+ ps1 = @mapper.prepare(:select, :something) { @mapper.filter(MockContent2, label: :$label) }
415
+ ps2 = @mapper.prepare(:select, :something) { @mapper.filter(MockContent2, label: :$label) }
416
+ ps1.object_id.must_equal ps2.object_id
417
+ ps0.object_id.wont_equal ps1.object_id
418
+ @mapper.scope(23, true) do
419
+ ps3 = @mapper.prepare(:select, :something) { @mapper.filter(MockContent2, label: :$label) }
420
+ ps1.object_id.wont_equal ps3.object_id
421
+ ps0.object_id.wont_equal ps3.object_id
422
+ end
423
+ end
424
+ @database.prepared_statements.values.map(&:sql).must_equal [
425
+ "SELECT * FROM content WHERE ((type_sid IN ('MockContent2')) AND (label = $label))",
426
+ "SELECT * FROM content WHERE ((hidden IS FALSE) AND (type_sid IN ('MockContent2')) AND (label = $label))",
427
+ "SELECT * FROM __r00023_content WHERE ((hidden IS FALSE) AND (type_sid IN ('MockContent2')) AND (label = $label))"
428
+ ]
429
+ end
430
+ end
431
+
400
432
  describe "models" do
401
433
  it "can clean the db completely" do
402
434
  def MockContent.types
@@ -941,27 +973,27 @@ describe "DataMapper" do
941
973
  before do
942
974
  @time = @table.dataset.send :format_timestamp, @now
943
975
  @database.columns = @expected_columns + [:created_at, :modified_at]
944
- TimestampedContent = Spontaneous::DataMapper::Model(:content, @database, @schema)
976
+ ::TimestampedContent = Spontaneous::DataMapper::Model(:content, @database, @schema)
945
977
  @database.sqls
946
978
  end
947
979
 
948
980
  after do
949
- DataMapperTest.send :remove_const, :TimestampedContent rescue nil
981
+ Object.send :remove_const, :TimestampedContent rescue nil
950
982
  end
951
983
 
952
984
  it "set created_at timestamp on creation" do
953
985
  instance = TimestampedContent.create label: "something"
954
- @database.sqls.first.must_equal "INSERT INTO content (label, created_at, type_sid) VALUES ('something', #{@time}, 'TimestampedContent')"
986
+ @database.sqls.first.must_equal "INSERT INTO content (label, created_at, modified_at, type_sid) VALUES ('something', #{@time}, #{@time}, 'TimestampedContent')"
955
987
  end
956
988
 
957
- # it "update the modified_at value on update" do
958
- # @database.fetch = { id: 1, type_sid:"TimestampedContent" }
959
- # instance = TimestampedContent.create label: "something"
960
- # @database.sqls
961
- # instance.set label: "changed"
962
- # instance.save
963
- # @database.sqls.first.must_equal "UPDATE content SET label = 'changed', modified_at = #{@time} WHERE (id = 1)"
964
- # end
989
+ it "update the modified_at value on update" do
990
+ @database.fetch = { id: 1, type_sid:"TimestampedContent" }
991
+ instance = TimestampedContent.create label: "something"
992
+ @database.sqls
993
+ instance.set label: "changed"
994
+ instance.save
995
+ @database.sqls.first.must_equal "UPDATE content SET label = 'changed', modified_at = #{@time} WHERE (id = 1)"
996
+ end
965
997
  end
966
998
 
967
999
  describe "schema" do
@@ -1015,6 +1047,7 @@ describe "DataMapper" do
1015
1047
  @database.fetch = { id: 7, type_sid:"AssocContent" }
1016
1048
  @parent = AssocContent.first
1017
1049
  @database.sqls
1050
+ @database.columns = nil
1018
1051
  end
1019
1052
 
1020
1053
  after do
@@ -1189,7 +1222,8 @@ describe "DataMapper" do
1189
1222
 
1190
1223
  describe "belongs_to associations" do
1191
1224
  before do
1192
- @database.columns = @expected_columns + [:parent_id]
1225
+ @columns = @expected_columns + [:parent_id]
1226
+ @database.columns = @columns
1193
1227
  AssocContent = Spontaneous::DataMapper::Model(:content, @database, @schema)
1194
1228
  AssocContent.has_many_content :children, key: :parent_id, reciprocal: :parent
1195
1229
  AssocContent.belongs_to_content :parent, key: :parent_id, reciprocal: :children
@@ -1197,6 +1231,8 @@ describe "DataMapper" do
1197
1231
 
1198
1232
  @child = AssocContent.first
1199
1233
  @database.sqls
1234
+ # reset the columns because it messes up prepared statments in the mock adapter
1235
+ @database.columns = nil
1200
1236
  end
1201
1237
 
1202
1238
  after do
@@ -1206,23 +1242,34 @@ describe "DataMapper" do
1206
1242
  it "load the owner" do
1207
1243
  @database.fetch = { id: 7, type_sid:"AssocContent", parent_id: nil }
1208
1244
  parent = @child.parent
1209
- @database.sqls.must_equal ["SELECT * FROM content WHERE ((type_sid IN ('MockContent2', 'MockContent3')) AND (id = 7)) LIMIT 1"]
1245
+ @database.sqls.must_equal ["SELECT * FROM content WHERE ((type_sid IN ('MockContent2', 'MockContent3')) AND (content.id = 7)) LIMIT 1"]
1246
+ parent.must_be_instance_of AssocContent
1247
+ parent.id.must_equal 7
1248
+ end
1249
+
1250
+ it "loads the owner in a revision" do
1251
+ @database.fetch = { id: 7, type_sid:"AssocContent", parent_id: nil }
1252
+ parent = nil
1253
+ @mapper.scope(23, true) do
1254
+ parent = @child.parent
1255
+ end
1256
+ @database.sqls.must_equal ["SELECT * FROM __r00023_content WHERE ((hidden IS FALSE) AND (type_sid IN ('MockContent2', 'MockContent3')) AND (__r00023_content.id = 7)) LIMIT 1"]
1210
1257
  parent.must_be_instance_of AssocContent
1211
1258
  parent.id.must_equal 7
1212
1259
  end
1213
1260
 
1214
1261
  it "cache the result" do
1215
1262
  parent = @child.parent
1216
- @database.sqls.must_equal ["SELECT * FROM content WHERE ((type_sid IN ('MockContent2', 'MockContent3')) AND (id = 7)) LIMIT 1"]
1263
+ @database.sqls.must_equal ["SELECT * FROM content WHERE ((type_sid IN ('MockContent2', 'MockContent3')) AND (content.id = 7)) LIMIT 1"]
1217
1264
  parent = @child.parent
1218
1265
  @database.sqls.must_equal [ ]
1219
1266
  end
1220
1267
 
1221
1268
  it "reload the result if asked" do
1222
1269
  parent = @child.parent
1223
- @database.sqls.must_equal ["SELECT * FROM content WHERE ((type_sid IN ('MockContent2', 'MockContent3')) AND (id = 7)) LIMIT 1"]
1270
+ @database.sqls.must_equal ["SELECT * FROM content WHERE ((type_sid IN ('MockContent2', 'MockContent3')) AND (content.id = 7)) LIMIT 1"]
1224
1271
  parent = @child.parent(reload: true)
1225
- @database.sqls.must_equal ["SELECT * FROM content WHERE ((type_sid IN ('MockContent2', 'MockContent3')) AND (id = 7)) LIMIT 1"]
1272
+ @database.sqls.must_equal ["SELECT * FROM content WHERE ((type_sid IN ('MockContent2', 'MockContent3')) AND (content.id = 7)) LIMIT 1"]
1226
1273
  end
1227
1274
 
1228
1275
  it "allow access to the relation dataset" do
@@ -1257,6 +1304,7 @@ describe "DataMapper" do
1257
1304
 
1258
1305
  describe "sequel models" do
1259
1306
  before do
1307
+ @database.columns = @columns
1260
1308
  ::Other = Class.new(Sequel::Model(:other)) do ; end
1261
1309
  Other.db = @database
1262
1310
  AssocContent.many_to_one :other, class: Other, key: :parent_id
@@ -1422,6 +1470,34 @@ describe "DataMapper" do
1422
1470
  assert a.object_id == b.object_id, "Mappers it be same object"
1423
1471
  end
1424
1472
 
1473
+ it "allows for passing any dataset to base a scope on" do
1474
+ ds = @database[:something].filter(socks: "green")
1475
+ @mapper.with(ds) do
1476
+ @mapper.get(23)
1477
+ end
1478
+ @database.sqls.must_equal [
1479
+ "SELECT * FROM something WHERE ((socks = 'green') AND (type_sid IN ('MockContent2', 'MockContent3')) AND (id = 23)) LIMIT 1"
1480
+ ]
1481
+ end
1482
+
1483
+ it "gives an empty revision & visibility setting for dataset scopes" do
1484
+ ds = @database[:something].filter(socks: "green")
1485
+ @mapper.scope(23, true) do
1486
+ @mapper.with(ds) do
1487
+ refute @mapper.visible_only?
1488
+ @mapper.current_revision.must_be_nil
1489
+ end
1490
+ end
1491
+ end
1492
+
1493
+ it "allows for separate configuration of revision & visibility" do
1494
+ ds = @database[:something].filter(socks: "green")
1495
+ @mapper.scope!(23, true, ds) do
1496
+ assert @mapper.visible_only?
1497
+ @mapper.current_revision.must_equal 23
1498
+ end
1499
+ end
1500
+
1425
1501
  it "allow for using a custom cache key" do
1426
1502
  @database.fetch = [
1427
1503
  { id: 20, type_sid:"MockContent", parent_id: 7 }