spontaneous 0.2.0.alpha2 → 0.2.0.alpha3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (404) hide show
  1. data/Gemfile +3 -40
  2. data/Rakefile +29 -41
  3. data/Readme.markdown +21 -8
  4. data/application/css/add_alias_dialogue.css.scss +79 -0
  5. data/application/css/{v2.scss → core.css.scss} +537 -550
  6. data/application/css/{definitions.scss → definitions.css.scss} +121 -33
  7. data/application/css/dialogue.css.scss +409 -0
  8. data/application/css/{editing.scss → editing.css.scss} +25 -262
  9. data/application/css/font.css.scss +8 -0
  10. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
  11. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
  12. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_flat_10_000000_40x100.png +0 -0
  13. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
  14. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
  15. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  16. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
  17. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
  18. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
  19. data/application/css/jquery-ui-1.8.21.custom/images/ui-icons_222222_256x240.png +0 -0
  20. data/application/css/jquery-ui-1.8.21.custom/images/ui-icons_228ef1_256x240.png +0 -0
  21. data/application/css/jquery-ui-1.8.21.custom/images/ui-icons_ef8c08_256x240.png +0 -0
  22. data/application/css/jquery-ui-1.8.21.custom/images/ui-icons_ffd27a_256x240.png +0 -0
  23. data/application/css/jquery-ui-1.8.21.custom/images/ui-icons_ffffff_256x240.png +0 -0
  24. data/application/css/jquery-ui-1.8.21.custom/ui-lightness.css.scss +565 -0
  25. data/application/css/{login.scss → login.css.scss} +4 -4
  26. data/application/css/meta.css.scss +331 -0
  27. data/application/css/{popover.scss → popover.css.scss} +9 -8
  28. data/application/css/{schema_error.scss → schema_error.css.scss} +4 -4
  29. data/application/css/spontaneous.css +5 -0
  30. data/application/css/unsupported.css.scss +42 -0
  31. data/application/js/add_alias_dialogue.js +72 -10
  32. data/application/js/ajax.js +50 -16
  33. data/application/js/compatibility.js +19 -15
  34. data/application/js/content.js +39 -36
  35. data/application/js/content_area.js +53 -5
  36. data/application/js/dialogue.js +17 -0
  37. data/application/js/dom.js +1 -1
  38. data/application/js/edit_panel.js +23 -8
  39. data/application/js/extensions.js +7 -2
  40. data/application/js/field_preview.js +2 -1
  41. data/application/js/field_types/date_field.js +11 -8
  42. data/application/js/field_types/file_field.js +188 -9
  43. data/application/js/field_types/image_field.js +46 -29
  44. data/application/js/field_types/markdown_field.js +57 -14
  45. data/application/js/field_types/select_field.js +72 -0
  46. data/application/js/field_types/string_field.js +8 -0
  47. data/application/js/field_types/webvideo_field.js +8 -0
  48. data/application/js/init.js +1 -7
  49. data/application/js/location.js +41 -13
  50. data/application/js/login.js +3 -0
  51. data/application/js/meta_view/user_admin.js +543 -0
  52. data/application/js/meta_view.js +1 -0
  53. data/application/js/metadata.js +20 -0
  54. data/application/js/page.js +17 -3
  55. data/application/js/page_browser.js +40 -30
  56. data/application/js/page_entry.js +4 -0
  57. data/application/js/panel/root_menu.js +66 -0
  58. data/application/js/popover.js +2 -2
  59. data/application/js/preview.js +1 -1
  60. data/application/js/publish.js +138 -30
  61. data/application/js/services.js +43 -0
  62. data/application/js/sharded_upload.js +2 -2
  63. data/application/js/spontaneous.js +64 -5
  64. data/application/js/state.js +20 -9
  65. data/application/js/top_bar.js +273 -150
  66. data/application/js/types.js +20 -15
  67. data/application/js/upload.js +1 -2
  68. data/application/js/user.js +18 -4
  69. data/application/js/vendor/date.js +104 -0
  70. data/application/js/vendor/jquery-ui-1.8.18.custom.min.js +356 -0
  71. data/application/js/views/box_view.js +15 -8
  72. data/application/js/views/page_piece_view.js +11 -8
  73. data/application/js/views/page_view.js +21 -3
  74. data/application/js/views/piece_view.js +19 -10
  75. data/application/js/views.js +3 -0
  76. data/application/static/chromelogo-200x52-45c7cbc93be080bea342df5fcda2ef8b.png +0 -0
  77. data/application/static/dot-texture-9eea29e4ac7ad9a772285252078ec127.png +0 -0
  78. data/application/static/editing-textarea-resize-s-b5af62365eb7e19ea4beccf7242d508e.png +0 -0
  79. data/application/static/editing-texture-1-42b06a3439752490988f30f2a06d5e7c.png +0 -0
  80. data/application/static/font/fontawesome-webfont-5c5c21100a346972a82c34c5e96ffcfe.ttf +0 -0
  81. data/application/static/loop_alt1-white-7894b458528e92216196cae26b4c2c96.svg +12 -0
  82. data/application/static/spontaneous-states-e91ec89db525c62da0105b97cdd781ce.png +0 -0
  83. data/application/views/index.erb +2 -2
  84. data/application/views/login.erb +4 -8
  85. data/application/views/schema_modification_error.html.erb +1 -4
  86. data/application/views/unsupported.erb +9 -7
  87. data/bin/spot +1 -1
  88. data/db/migrations/20110209152710_users_and_groups.rb +10 -10
  89. data/db/migrations/20120305112647_site_modification_time.rb +11 -0
  90. data/db/migrations/20120418153903_add_ownership_of_content.rb +14 -0
  91. data/db/migrations/20120423175416_add_pending_modifications.rb +21 -0
  92. data/db/migrations/20120525164947_add_field_versions.rb +27 -0
  93. data/lib/sequel/plugins/scoped_table_name.rb +10 -1
  94. data/lib/spontaneous/asset/file.rb +25 -0
  95. data/lib/spontaneous/asset/source.rb +28 -0
  96. data/lib/spontaneous/asset.rb +75 -0
  97. data/lib/spontaneous/box.rb +6 -4
  98. data/lib/spontaneous/capistrano/deploy.rb +47 -0
  99. data/lib/spontaneous/capistrano/sync.rb +81 -0
  100. data/lib/spontaneous/capistrano.rb +13 -0
  101. data/lib/spontaneous/change.rb +60 -68
  102. data/lib/spontaneous/cli/assets.rb +29 -0
  103. data/lib/spontaneous/cli/base.rb +0 -48
  104. data/lib/spontaneous/cli/console.rb +1 -1
  105. data/lib/spontaneous/cli/server.rb +6 -4
  106. data/lib/spontaneous/cli/site.rb +28 -17
  107. data/lib/spontaneous/cli/user.rb +107 -0
  108. data/lib/spontaneous/cli.rb +100 -4
  109. data/lib/spontaneous/collections/entry_set.rb +2 -2
  110. data/lib/spontaneous/collections/field_set.rb +48 -22
  111. data/lib/spontaneous/collections/prototype_set.rb +20 -13
  112. data/lib/spontaneous/constants.rb +3 -0
  113. data/lib/spontaneous/content.rb +22 -5
  114. data/lib/spontaneous/errors.rb +3 -3
  115. data/lib/spontaneous/extensions/array.rb +12 -0
  116. data/lib/spontaneous/extensions/enumerable.rb +30 -0
  117. data/lib/spontaneous/extensions/nil.rb +3 -1
  118. data/lib/spontaneous/extensions/string.rb +16 -0
  119. data/lib/spontaneous/field_types/date_field.rb +45 -2
  120. data/lib/spontaneous/field_types/field.rb +42 -9
  121. data/lib/spontaneous/field_types/file_field.rb +68 -0
  122. data/lib/spontaneous/field_types/image_field.rb +63 -0
  123. data/lib/spontaneous/field_types/select_field.rb +109 -0
  124. data/lib/spontaneous/field_types/string_field.rb +6 -1
  125. data/lib/spontaneous/field_types/webvideo_field.rb +85 -27
  126. data/lib/spontaneous/field_types.rb +1 -1
  127. data/lib/spontaneous/field_version.rb +8 -0
  128. data/lib/spontaneous/generators/page.rb +1 -1
  129. data/lib/spontaneous/generators/site/Capfile.tt +1 -4
  130. data/lib/spontaneous/generators/site/Gemfile.tt +13 -6
  131. data/lib/spontaneous/generators/site/config/deploy.rb.tt +28 -0
  132. data/lib/spontaneous/generators/site/config/environments/production.rb.tt +7 -2
  133. data/lib/spontaneous/generators/site.rb +1 -0
  134. data/lib/spontaneous/json.rb +34 -11
  135. data/lib/spontaneous/layout.rb +22 -0
  136. data/lib/spontaneous/media/file.rb +4 -0
  137. data/lib/spontaneous/output/assets/compression.rb +58 -0
  138. data/lib/spontaneous/output/assets.rb +32 -0
  139. data/lib/spontaneous/output/context.rb +179 -0
  140. data/lib/spontaneous/output/format/html.rb +5 -0
  141. data/lib/spontaneous/output/format/plain.rb +5 -0
  142. data/lib/spontaneous/output/format.rb +180 -0
  143. data/lib/spontaneous/output/helpers/classes_helper.rb +18 -0
  144. data/lib/spontaneous/{render/helpers/html_helper.rb → output/helpers/conditional_comment_helper.rb} +3 -12
  145. data/lib/spontaneous/output/helpers/script_helper.rb +73 -0
  146. data/lib/spontaneous/output/helpers/stylesheet_helper.rb +61 -0
  147. data/lib/spontaneous/output/helpers.rb +28 -0
  148. data/lib/spontaneous/output/template/engine.rb +59 -0
  149. data/lib/spontaneous/output/template/renderer.rb +153 -0
  150. data/lib/spontaneous/output/template.rb +21 -0
  151. data/lib/spontaneous/output.rb +163 -0
  152. data/lib/spontaneous/page.rb +2 -1
  153. data/lib/spontaneous/paths.rb +6 -1
  154. data/lib/spontaneous/permissions/access_key.rb +5 -5
  155. data/lib/spontaneous/permissions/user.rb +81 -35
  156. data/lib/spontaneous/permissions/user_level.rb +26 -22
  157. data/lib/spontaneous/plugins/aliases.rb +76 -12
  158. data/lib/spontaneous/plugins/allowed_types.rb +60 -18
  159. data/lib/spontaneous/plugins/application/paths.rb +0 -28
  160. data/lib/spontaneous/plugins/application/system.rb +35 -0
  161. data/lib/spontaneous/plugins/boxes.rb +4 -0
  162. data/lib/spontaneous/plugins/content_groups.rb +16 -0
  163. data/lib/spontaneous/plugins/entries.rb +50 -30
  164. data/lib/spontaneous/plugins/fields.rb +15 -0
  165. data/lib/spontaneous/plugins/layouts.rb +8 -2
  166. data/lib/spontaneous/plugins/modifications.rb +228 -0
  167. data/lib/spontaneous/plugins/page/formats.rb +67 -42
  168. data/lib/spontaneous/plugins/page/request.rb +10 -0
  169. data/lib/spontaneous/plugins/page/site_timestamps.rb +28 -0
  170. data/lib/spontaneous/plugins/paths.rb +15 -3
  171. data/lib/spontaneous/plugins/publishing.rb +124 -45
  172. data/lib/spontaneous/plugins/render.rb +13 -8
  173. data/lib/spontaneous/plugins/schema_hierarchy.rb +18 -6
  174. data/lib/spontaneous/plugins/site/helpers.rb +53 -0
  175. data/lib/spontaneous/plugins/site/hooks.rb +50 -0
  176. data/lib/spontaneous/plugins/site/map.rb +1 -1
  177. data/lib/spontaneous/plugins/site/paths.rb +13 -0
  178. data/lib/spontaneous/plugins/site/publishing.rb +6 -2
  179. data/lib/spontaneous/plugins/site/{revisions.rb → state.rb} +5 -1
  180. data/lib/spontaneous/plugins/site/storage.rb +4 -0
  181. data/lib/spontaneous/plugins/site/url.rb +15 -0
  182. data/lib/spontaneous/plugins/site_map.rb +13 -3
  183. data/lib/spontaneous/plugins/styles.rb +5 -1
  184. data/lib/spontaneous/plugins/visibility.rb +39 -12
  185. data/lib/spontaneous/prototypes/box_prototype.rb +4 -0
  186. data/lib/spontaneous/prototypes/field_prototype.rb +15 -10
  187. data/lib/spontaneous/publishing/event_client.rb +46 -0
  188. data/lib/spontaneous/publishing/immediate.rb +81 -44
  189. data/lib/spontaneous/publishing/simultaneous.rb +23 -6
  190. data/lib/spontaneous/publishing.rb +4 -3
  191. data/lib/spontaneous/rack/around_back.rb +1 -5
  192. data/lib/spontaneous/rack/around_front.rb +4 -4
  193. data/lib/spontaneous/rack/around_preview.rb +4 -3
  194. data/lib/spontaneous/rack/assets.rb +81 -54
  195. data/lib/spontaneous/rack/authentication.rb +0 -1
  196. data/lib/spontaneous/rack/back.rb +160 -72
  197. data/lib/spontaneous/rack/cookie_authentication.rb +2 -2
  198. data/lib/spontaneous/rack/css.rb +18 -15
  199. data/lib/spontaneous/rack/event_source.rb +9 -21
  200. data/lib/spontaneous/rack/fiber_pool.rb +26 -0
  201. data/lib/spontaneous/rack/front.rb +12 -4
  202. data/lib/spontaneous/rack/helpers.rb +35 -13
  203. data/lib/spontaneous/rack/js.rb +41 -0
  204. data/lib/spontaneous/rack/public.rb +34 -44
  205. data/lib/spontaneous/rack/sse.rb +18 -0
  206. data/lib/spontaneous/rack/static.rb +3 -0
  207. data/lib/spontaneous/rack/user_admin.rb +100 -0
  208. data/lib/spontaneous/rack/user_helpers.rb +1 -1
  209. data/lib/spontaneous/rack.rb +6 -2
  210. data/lib/spontaneous/schema.rb +31 -4
  211. data/lib/spontaneous/search/index.rb +19 -3
  212. data/lib/spontaneous/search/results.rb +1 -1
  213. data/lib/spontaneous/sequel.rb +17 -0
  214. data/lib/spontaneous/site.rb +11 -4
  215. data/lib/spontaneous/state.rb +11 -0
  216. data/lib/spontaneous/storage/cloud.rb +4 -0
  217. data/lib/spontaneous/storage/local.rb +11 -0
  218. data/lib/spontaneous/style.rb +2 -2
  219. data/lib/spontaneous/tasks/database.rake +21 -22
  220. data/lib/spontaneous/utils/database/mysql_dumper.rb +4 -0
  221. data/lib/spontaneous/utils/database/postgres_dumper.rb +78 -0
  222. data/lib/spontaneous/utils/database.rb +6 -3
  223. data/lib/spontaneous/utils/smart_quotes.rb +499 -0
  224. data/lib/spontaneous/utils/smush_it.rb +66 -0
  225. data/lib/spontaneous/utils.rb +3 -1
  226. data/lib/spontaneous/version.rb +2 -2
  227. data/lib/spontaneous.rb +25 -29
  228. data/spontaneous.gemspec +186 -106
  229. data/test/experimental/test_features.rb +1 -1
  230. data/test/fixtures/asset_pipeline/application/css/basic.css.scss +4 -0
  231. data/test/fixtures/asset_pipeline/application/css/complex.css.scss.erb +6 -0
  232. data/test/fixtures/asset_pipeline/application/css/simple.css +3 -0
  233. data/test/fixtures/asset_pipeline/application/css/spontaneous.css +7 -0
  234. data/test/fixtures/asset_pipeline/application/css/subdir/complex.css.scss.erb +6 -0
  235. data/test/fixtures/asset_pipeline/application/css/subdir/library.css.scss +1 -0
  236. data/test/fixtures/asset_pipeline/application/css/subdir/simple.css +3 -0
  237. data/test/fixtures/asset_pipeline/application/js/basic.js.coffee +1 -0
  238. data/test/fixtures/asset_pipeline/application/js/complex.js.coffee.erb +1 -0
  239. data/test/fixtures/asset_pipeline/application/js/login.js +1 -0
  240. data/test/fixtures/asset_pipeline/application/js/require.js +1 -0
  241. data/test/fixtures/asset_pipeline/application/js/simple.js +1 -0
  242. data/test/fixtures/asset_pipeline/application/js/spontaneous.js +5 -0
  243. data/test/fixtures/asset_pipeline/application/js/subdir/complex.js.coffee.erb +1 -0
  244. data/test/fixtures/asset_pipeline/application/js/subdir/library.js.coffee +1 -0
  245. data/test/fixtures/asset_pipeline/application/js/subdir/simple.js +1 -0
  246. data/test/fixtures/asset_pipeline/application/js/vendor/jquery.js +1 -0
  247. data/test/fixtures/asset_pipeline/application/static/dot-texture.png +0 -0
  248. data/test/fixtures/asset_pipeline/application/static/subdir/px.gif +0 -0
  249. data/test/fixtures/assets/public1/css/a.scss +1 -0
  250. data/test/fixtures/assets/public1/js/a.js +1 -0
  251. data/test/fixtures/assets/public1/js/m.coffee +1 -0
  252. data/test/fixtures/assets/public2/css/b.scss +1 -0
  253. data/test/fixtures/assets/public2/css/c.css +1 -0
  254. data/test/fixtures/assets/public2/js/b.js +1 -0
  255. data/test/fixtures/assets/public2/js/c.js +1 -0
  256. data/test/fixtures/assets/public2/js/n.coffee +1 -0
  257. data/test/fixtures/back/config/user_levels.yml +3 -0
  258. data/test/fixtures/back/public/js/coffeescript.coffee +1 -0
  259. data/test/fixtures/back/templates/layouts/standard.css.cut +1 -0
  260. data/test/fixtures/back/templates/layouts/standard.js.cut +1 -0
  261. data/test/fixtures/example_application/config/database.yml +4 -4
  262. data/test/fixtures/helpers/templates/layouts/standard.html.cut +1 -0
  263. data/test/fixtures/helpers/templates/layouts/standard.mobile.cut +1 -0
  264. data/test/fixtures/images/vimlogo.pdf +0 -0
  265. data/test/fixtures/outputs/templates/layouts/standard.atom.cut +1 -0
  266. data/test/fixtures/permissions/config/user_levels.yml +6 -3
  267. data/test/fixtures/serialisation/class_hash.yaml.erb +1 -0
  268. data/test/fixtures/serialisation/root_hash.yaml.erb +2 -2
  269. data/test/fixtures/templates/extended/grandparent.html.cut +7 -7
  270. data/test/fixtures/templates/extended/main.html.cut +5 -5
  271. data/test/fixtures/templates/extended/parent.html.cut +8 -8
  272. data/test/fixtures/templates/extended/partial_with_locals.html.cut +1 -1
  273. data/test/fixtures/templates/extended/with_includes.html.cut +6 -6
  274. data/test/fixtures/templates/extended/with_includes_and_locals.html.cut +6 -7
  275. data/test/fixtures/templates/layouts/entries.html.cut +4 -4
  276. data/test/fixtures/templates/layouts/standard.html.cut +1 -0
  277. data/test/fixtures/templates/layouts/variables.html.cut +1 -1
  278. data/test/fixtures/templates/publishing/templates/layouts/static.html.cut +1 -1
  279. data/test/fixtures/templates/publishing/templates/layouts/static.rtf.cut +1 -0
  280. data/test/fixtures/templates/template_class/complex_template.html.cut +2 -2
  281. data/test/fixtures/templates/template_class/complex_template.pdf.cut +2 -2
  282. data/test/fixtures/templates/template_class/default_template_style.html.cut +1 -1
  283. data/test/fixtures/templates/template_class/images_with_template.html.cut +2 -2
  284. data/test/fixtures/templates/template_class/slots_template.html.cut +2 -2
  285. data/test/fixtures/templates/template_class/slots_template.pdf.cut +2 -2
  286. data/test/fixtures/user_manager/config/user_levels.yml +9 -0
  287. data/test/functional/test_application.rb +7 -7
  288. data/test/functional/test_back.rb +352 -97
  289. data/test/functional/test_front.rb +71 -20
  290. data/test/functional/test_user_manager.rb +284 -0
  291. data/test/javascript/env.js +13505 -0
  292. data/test/javascript/test_markdown.rb +43 -3
  293. data/test/support/custom_matchers.rb +3 -2
  294. data/test/test_helper.rb +50 -9
  295. data/test/test_javascript.rb +13 -13
  296. data/test/ui_helper.rb +1 -1
  297. data/test/unit/test_alias.rb +79 -8
  298. data/test/unit/test_asset_bundler.rb +220 -0
  299. data/test/unit/test_assets.rb +213 -0
  300. data/test/unit/test_async.rb +55 -0
  301. data/test/unit/test_authentication.rb +52 -39
  302. data/test/unit/test_boxes.rb +20 -15
  303. data/test/unit/test_changesets.rb +261 -0
  304. data/test/unit/test_content.rb +73 -33
  305. data/test/unit/test_content_inheritance.rb +18 -18
  306. data/test/unit/test_extensions.rb +26 -0
  307. data/test/unit/test_fields.rb +303 -16
  308. data/test/unit/test_formats.rb +267 -34
  309. data/test/unit/test_helpers.rb +79 -2
  310. data/test/unit/test_images.rb +10 -0
  311. data/test/unit/test_layouts.rb +21 -13
  312. data/test/unit/test_modifications.rb +648 -0
  313. data/test/unit/test_page.rb +6 -2
  314. data/test/unit/test_permissions.rb +101 -27
  315. data/test/unit/test_piece.rb +4 -4
  316. data/test/unit/test_plugins.rb +3 -2
  317. data/test/unit/test_publishing.rb +332 -0
  318. data/test/unit/test_render.rb +118 -67
  319. data/test/unit/test_revisions.rb +546 -0
  320. data/test/unit/test_schema.rb +83 -1
  321. data/test/unit/test_search.rb +59 -0
  322. data/test/unit/test_serialisation.rb +2 -47
  323. data/test/unit/test_site.rb +217 -108
  324. data/test/unit/test_storage.rb +26 -0
  325. data/test/unit/test_structure.rb +2 -2
  326. data/test/unit/test_styles.rb +90 -75
  327. data/test/unit/test_table_scoping.rb +21 -17
  328. data/test/unit/test_templates.rb +75 -69
  329. data/test/{slow → unit}/test_visibility.rb +78 -22
  330. metadata +528 -221
  331. data/application/css/add_alias_dialogue.scss +0 -27
  332. data/application/css/min/14c2a35812c443001b15d8b12a4780f88c678035.css +0 -1
  333. data/application/css/min/565d4c25e82148acb01c45c8d675b37a08676d77.css +0 -1
  334. data/application/css/min/84dbe894ea96eafd321c30823d630817bfc4b03b.css +0 -1
  335. data/application/css/spontaneous.scss +0 -111
  336. data/application/css/unsupported.scss +0 -16
  337. data/application/css/variables.scss +0 -80
  338. data/application/js/min/2a0c2962537a3181fedfff5c92596ba6d3122dc9.js +0 -3
  339. data/application/js/min/4cf1c493d3379ecba5287758c61238034c0893f9.js +0 -2
  340. data/application/js/min/78ac6b99d96750bb6b9f9aad4cb9cd91cd03f391.js +0 -3
  341. data/application/js/min/b8abf302a824c35385ff517b34111e1710ff3b37.js +0 -2
  342. data/application/js/min/c8efb9b9f7c3f6613fcebc6be60f605b6570a382.js +0 -90
  343. data/application/static/diagonal-texture.png +0 -0
  344. data/application/static/editing-0-noise.png +0 -0
  345. data/application/static/editing-1-noise.png +0 -0
  346. data/application/static/editing-texture-1.png +0 -0
  347. data/application/static/editing-texture.png +0 -0
  348. data/application/static/editing-toolbar-shadow-bottom.png +0 -0
  349. data/application/static/editing-toolbar-shadow-top.png +0 -0
  350. data/application/static/inner-glow.png +0 -0
  351. data/application/static/item-buttons-highlight.png +0 -0
  352. data/application/static/item-buttons.png +0 -0
  353. data/application/static/paper-texture-dark.png +0 -0
  354. data/application/static/plus_alt.svg +0 -8
  355. data/application/static/select-arrow-root.png +0 -0
  356. data/application/static/slot-up-arrow.png +0 -0
  357. data/application/static/spontaneous.png +0 -0
  358. data/lib/cutaneous/context_helper.rb +0 -187
  359. data/lib/cutaneous/preview_context.rb +0 -32
  360. data/lib/cutaneous/preview_renderer.rb +0 -10
  361. data/lib/cutaneous/publish_context.rb +0 -10
  362. data/lib/cutaneous/publish_renderer.rb +0 -14
  363. data/lib/cutaneous/publish_template.rb +0 -62
  364. data/lib/cutaneous/publish_token_parser.rb +0 -8
  365. data/lib/cutaneous/renderer.rb +0 -124
  366. data/lib/cutaneous/request_context.rb +0 -9
  367. data/lib/cutaneous/request_renderer.rb +0 -15
  368. data/lib/cutaneous/request_template.rb +0 -11
  369. data/lib/cutaneous/request_token_parser.rb +0 -9
  370. data/lib/cutaneous/token_parser.rb +0 -125
  371. data/lib/cutaneous.rb +0 -48
  372. data/lib/spontaneous/render/context_base.rb +0 -143
  373. data/lib/spontaneous/render/development_renderer.rb +0 -14
  374. data/lib/spontaneous/render/engine.rb +0 -19
  375. data/lib/spontaneous/render/format/html.rb +0 -5
  376. data/lib/spontaneous/render/format.rb +0 -75
  377. data/lib/spontaneous/render/helpers/script_helper.rb +0 -17
  378. data/lib/spontaneous/render/helpers/stylesheet_helper.rb +0 -16
  379. data/lib/spontaneous/render/helpers.rb +0 -14
  380. data/lib/spontaneous/render/preview_context.rb +0 -8
  381. data/lib/spontaneous/render/preview_renderer.rb +0 -24
  382. data/lib/spontaneous/render/publish_context.rb +0 -22
  383. data/lib/spontaneous/render/published_renderer.rb +0 -53
  384. data/lib/spontaneous/render/publishing_renderer.rb +0 -16
  385. data/lib/spontaneous/render/render_cache.rb +0 -26
  386. data/lib/spontaneous/render/renderer.rb +0 -50
  387. data/lib/spontaneous/render/request_context.rb +0 -8
  388. data/lib/spontaneous/render.rb +0 -214
  389. data/test/experimental/test_cutaneous.rb +0 -309
  390. data/test/fixtures/application/css/test.less +0 -5
  391. data/test/slow/test_publishing.rb +0 -1006
  392. /data/application/css/{developer.scss → developer.css.scss} +0 -0
  393. /data/application/js/vendor/{jquery-1.7.1.min.js → jquery.js} +0 -0
  394. /data/application/static/{location-arrow.png → location-arrow-c1c1d3ca472481c61a0a5f8cb289d743.png} +0 -0
  395. /data/application/static/{missing.png → missing-911ce6dbd9f4602e0f3fbcd7e78846a2.png} +0 -0
  396. /data/application/static/{orange-down-arrow.png → orange-down-arrow-395ae1929e8662b2ff0977daf12c35bb.png} +0 -0
  397. /data/application/static/{page-browser-next.png → page-browser-next-ce781a242c23b980b99b9db7abc20b05.png} +0 -0
  398. /data/application/static/{plus-box.png → plus-box-dcde74a1e496f68298c9b443caa1c5d5.png} +0 -0
  399. /data/application/static/{select-arrow.png → select-arrow-6e7dd3745b00e934b0d7a3250c46558b.png} +0 -0
  400. /data/application/static/{slot-down-arrow.png → slot-down-arrow-59ad5f5ee5b52a7ebd00bca4b3104194.png} +0 -0
  401. /data/application/static/{splash.png → splash-65b493a714df9b8b3ab170103401b53d.png} +0 -0
  402. /data/application/static/{spot.png → spot-71fab1d2f065034f5fc15e7bea2ad36c.png} +0 -0
  403. /data/application/static/{spot.svg → spot-8505041082d8d3bbe8d34c29dddb3b7d.svg} +0 -0
  404. /data/application/static/{texture.png → texture-03f7627e8264b1d607113ab32c593a58.png} +0 -0
@@ -0,0 +1,107 @@
1
+
2
+ module Spontaneous
3
+ module Cli
4
+ class User < ::Spontaneous::Cli::Thor
5
+ Spontaneous = ::Spontaneous
6
+ namespace :user
7
+
8
+ default_task :add
9
+
10
+ desc "#{namespace}:add", "Add a new user"
11
+
12
+ method_option :login, :type => :string, :aliases => "-l",
13
+ :desc => "The user's login -- must be unique"
14
+ method_option :name, :type => :string, :aliases => "-n",
15
+ :desc => "The user's name"
16
+ method_option :email, :type => :string, :aliases => "-e",
17
+ :desc => "The user's email address"
18
+ method_option :passwd, :type => :string, :aliases => ["-p", "--password"],
19
+ :desc => "The user's password"
20
+ method_option :level, :type => :string, :aliases => "-a",
21
+ :desc => "The user's access level"
22
+
23
+ def add
24
+ prepare :adduser, :console
25
+ boot!
26
+ users = Spontaneous::Permissions::User.count
27
+ attrs = {}
28
+ width = 14
29
+ valid_login = /^[a-z0-9_]{3,}$/
30
+ levels = Spontaneous::Permissions::UserLevel.all.map(&:to_s)
31
+ level = nil
32
+
33
+ say("\nAll fields are required:\n", :green)
34
+ if options.login
35
+ attrs[:login] = options.login
36
+ say "Login : ".rjust(width, " ")+" ", :white
37
+ say options.login, :green
38
+ else
39
+ begin
40
+ attrs[:login] = ask "Login : ".rjust(width, " ")
41
+ say("Login must consist of at least 3 letters, numbers and underscores", :red) unless valid_login === attrs[:login]
42
+ end while attrs[:login] !~ valid_login
43
+ end
44
+
45
+ attrs[:name] = options.name || ask("Name : ".rjust(width, " "))
46
+
47
+ if options.name
48
+ say "Name : ".rjust(width, " ")+" ", :white
49
+ say options.name, :green
50
+ end
51
+
52
+ attrs[:email] = options.email || ask("Email : ".rjust(width, " "))
53
+
54
+ if options.email
55
+ say "Email : ".rjust(width, " ")+" ", :white
56
+ say options.email, :green
57
+ end
58
+
59
+ if options.passwd
60
+ attrs[:password] = options.passwd
61
+ say "Password : ".rjust(width, " ")+" ", :white
62
+ say options.passwd, :green
63
+ else
64
+ begin
65
+ attrs[:password] = ask "Password : ".rjust(width, " ")
66
+ say("Password must be at least 6 characters long", :red) unless attrs[:password].length > 5
67
+ end while attrs[:password].length < 6
68
+ end
69
+
70
+
71
+ if users == 0
72
+ level = "root"
73
+ else
74
+ if options.level
75
+ level = options.level
76
+ say "User level : ".rjust(width, " ")+" ", :white
77
+ say options.level, :green
78
+ unless levels.include?(level)
79
+ say("\nInvalid level '#{level}'", :red)
80
+ say("Valid levels are: #{levels.join(", ")}", :red)
81
+ exit 127
82
+ end
83
+ else
84
+ begin
85
+ level = ask("User level [#{levels.join(', ')}] : ")
86
+ say("Invalid level '#{level}'", :red) unless levels.include?(level)
87
+ end while !levels.include?(level)
88
+ end
89
+ end
90
+
91
+ user = Spontaneous::Permissions::User.new(attrs)
92
+
93
+ if user.save
94
+ user.update(:level => level)
95
+ say("\nUser '#{user.login}' created with level '#{user.level}'", :green)
96
+ else
97
+ errors = user.errors.map do | a, e |
98
+ " - '#{a.to_s.capitalize}' #{e.first}"
99
+ end.join("\n")
100
+ say("\nInvalid user details:\n"+errors, :red)
101
+ exit 127
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
107
+
@@ -42,14 +42,14 @@ module Spontaneous
42
42
  end
43
43
  end
44
44
 
45
- def prepare(task)
45
+ def prepare(task, mode = nil)
46
46
  if options.help?
47
47
  help(task.to_s)
48
48
  raise SystemExit
49
49
  end
50
50
  ENV["SPOT_ENV"] ||= options.environment.to_s
51
51
  ENV["RACK_ENV"] = ENV["SPOT_ENV"] # Also set this for middleware
52
- ENV["SPOT_MODE"] ||= options.mode.to_s
52
+ ENV["SPOT_MODE"] = mode.to_s unless mode.nil?
53
53
  chdir(options.site)
54
54
  unless File.exist?('config/boot.rb')
55
55
  puts "=> Could not find boot file in: #{options.chdir}/config/boot.rb\n=> Are you sure this is a Spontaneous site?"
@@ -69,11 +69,106 @@ module Spontaneous
69
69
  end
70
70
  end
71
71
 
72
- class Runner < ::Thor::Runner
73
- remove_task :install#, :undefine => true
72
+ class Runner < ::Thor
73
+ namespace "default"
74
+
75
+ remove_task :help
76
+
77
+ map %w(-T) => :list, %w(--version -v) => :version
78
+
79
+ desc "version", "Show Spontaneous version"
80
+ def version
81
+ require 'spontaneous/version'
82
+ say "Spontaneous #{Spontaneous::VERSION}"
83
+ end
84
+
85
+ desc "list [SEARCH]", "List the available tasks (--substring means .*SEARCH)"
86
+ method_options :substring => :boolean, :group => :string, :all => :boolean, :debug => :boolean
87
+ def list(search="")
88
+ initialize_thorfiles
89
+
90
+ search = ".*#{search}" if options["substring"]
91
+ search = /^#{search}.*/i
92
+ group = options[:group] || "standard"
93
+
94
+ klasses = Thor::Base.subclasses.select do |k|
95
+ (options[:all] || k.group == group) && k.namespace =~ search
96
+ end
97
+
98
+ display_klasses(false, false, klasses)
99
+ end
100
+
101
+ # Override Thor#help so it can give information about any class and any method.
102
+ #
103
+ desc "help [TASK]", "Describe available tasks or one specific task"
104
+ def help(task = nil, subcommand = false)
105
+ task ? self.class.task_help(shell, task) : self.class.help(shell, subcommand)
106
+ end
107
+
108
+
109
+ # Override Thor#help so it can give information about any class and any method.
110
+ #
111
+ def help(meth = nil)
112
+ if meth && !self.respond_to?(meth)
113
+ initialize_thorfiles(meth)
114
+ klass, task = Thor::Util.find_class_and_task_by_namespace(meth)
115
+ klass.start(["-h", task].compact, :shell => self.shell)
116
+ else
117
+ list
118
+ end
119
+ end
120
+
121
+ # If a task is not found on Thor::Runner, method missing is invoked and
122
+ # Thor::Runner is then responsable for finding the task in all classes.
123
+ #
124
+ def method_missing(meth, *args)
125
+ meth = meth.to_s
126
+ initialize_thorfiles(meth)
127
+ klass, task = Thor::Util.find_class_and_task_by_namespace(meth)
128
+ args.unshift(task) if task
129
+ klass.start(args, :shell => self.shell)
130
+ end
74
131
 
75
132
  private
76
133
 
134
+ # Display information about the given klasses. If with_module is given,
135
+ # it shows a table with information extracted from the yaml file.
136
+ #
137
+ def display_klasses(with_modules=false, show_internal=false, klasses=Thor::Base.subclasses)
138
+ klasses -= [Thor, Thor::Runner, Thor::Group] unless show_internal
139
+
140
+ raise Error, "No tasks available" if klasses.empty?
141
+ show_modules if with_modules && !thor_yaml.empty?
142
+
143
+ list = Hash.new { |h,k| h[k] = [] }
144
+ groups = klasses.select { |k| k.ancestors.include?(Thor::Group) }
145
+
146
+ # Get classes which inherit from Thor
147
+ (klasses - groups).each { |k| list[k.namespace.split(":").first] += k.printable_tasks(false) }
148
+
149
+ list.delete("thor")
150
+
151
+ # Order namespaces with default coming first
152
+ list = list.sort{ |a,b| a[0].sub(/^default/, '') <=> b[0].sub(/^default/, '') }
153
+ list.each { |n, tasks| display_tasks(n, tasks) unless tasks.empty? }
154
+ end
155
+
156
+ def display_tasks(namespace, list) #:nodoc:
157
+ list.sort!{ |a,b| a[0] <=> b[0] }
158
+
159
+ say shell.set_color(namespace, :blue, true)
160
+ say "-" * namespace.size
161
+
162
+ print_table(list, :truncate => true)
163
+ say
164
+ end
165
+
166
+ def initialize_thorfiles(relevant_to=nil, skip_lookup=false)
167
+ thorfiles(relevant_to, skip_lookup).each do |f|
168
+ Thor::Util.load_thorfile(f, nil, options[:debug]) unless Thor::Base.subclass_files.keys.include?(File.expand_path(f))
169
+ end
170
+ end
171
+
77
172
  def thorfiles(*args)
78
173
  task_dir = File.expand_path('../cli', __FILE__)
79
174
  Dir["#{task_dir}/*.rb"]
@@ -83,6 +178,7 @@ module Spontaneous
83
178
  autoload :Adapter, "spontaneous/cli/adapter"
84
179
  autoload :Base, "spontaneous/cli/base"
85
180
  autoload :Site, "spontaneous/cli/site"
181
+ autoload :User, "spontaneous/cli/user"
86
182
  end
87
183
  end
88
184
 
@@ -65,9 +65,9 @@ module Spontaneous::Collections
65
65
  owner.entry_modified!(nil)
66
66
  end
67
67
 
68
- def destroy
68
+ def destroy(origin)
69
69
  store.each do |box_id, entries|
70
- entries.dup.each { |e| e.destroy(false) }
70
+ entries.dup.each { |e| e.destroy(false, origin) }
71
71
  end
72
72
  end
73
73
 
@@ -8,45 +8,71 @@ module Spontaneous::Collections
8
8
  def initialize(owner, initial_values)
9
9
  super()
10
10
  @owner = owner
11
- initialize_from_prototypes(initial_values)
11
+ @field_data = initial_values
12
+ initialize_from_prototypes
12
13
  end
13
14
 
14
- def initialize_from_prototypes(initial_values)
15
- values = (initial_values || []).map do |value|
16
- value = S::FieldTypes.deserialize_field(value)
17
- [Spontaneous.schema.uids[value[:id]], value]
18
- end
19
- values = Hash[values]
20
- owner.field_prototypes.each do |field_prototype|
21
- field = field_prototype.to_field(values[field_prototype.schema_id])
22
- add_field(field)
23
- end
24
- end
25
15
 
26
16
  def serialize_db
27
17
  self.map { |field| field.serialize_db }
28
18
  end
29
19
 
30
20
  def export(user)
31
- owner.class.field_names.map do |name|
32
- self[name].export(user)
33
- end
21
+ owner.class.field_names.
22
+ select { |name| owner.field_writable?(user, name) }.
23
+ map { |name| self[name].export(user) }
34
24
  end
35
25
 
36
26
  def saved
37
27
  self.each { |field| field.mark_unmodified }
38
28
  end
39
29
 
30
+ # Lazily load fields by name
31
+ def named(name)
32
+ super || load_field(owner.field_prototypes[name.to_sym])
33
+ end
34
+
40
35
  protected
41
36
 
42
- def add_field(field)
43
- field.owner = owner
44
- getter_name = field.name
45
- setter_name = "#{field.name}="
46
- self[field.name.to_sym] = field
37
+ def initialize_from_prototypes
38
+ owner.field_prototypes.each do |field_prototype|
39
+ add_field(field_prototype)
40
+ end
41
+ end
42
+
43
+ def field_values
44
+ @field_values ||= parse_field_data(@field_data)
45
+ end
46
+
47
+ def parse_field_data(initial_values)
48
+ values = (initial_values || []).map do |value|
49
+ value = S::FieldTypes.deserialize_field(value)
50
+ [Spontaneous.schema.uids[value[:id]], value]
51
+ end
52
+ Hash[values]
53
+ end
54
+
55
+ # overwritten because otherwise the iterators in PrototypeSet don't
56
+ # know which keys we are supposed to have
57
+ def local_order
58
+ owner.field_prototypes.keys
59
+ end
60
+
61
+ def add_field(field_prototype)
62
+ name = field_prototype.name
63
+ getter_name = name
64
+ setter_name = "#{name}="
47
65
  singleton_class.class_eval do
48
- define_method(getter_name) { |*args| field.tap { |f| f.template_params = args } }
49
- define_method(setter_name) { |value| field.value = value }
66
+ define_method(getter_name) { |*args| named(name).tap { |f| f.template_params = args } }
67
+ define_method(setter_name) { |value| named(name).value = value }
68
+ end
69
+ end
70
+
71
+ def load_field(field_prototype)
72
+ return nil if field_prototype.nil?
73
+ field_prototype.to_field(owner, field_values[field_prototype.schema_id]).tap do |field|
74
+ field.owner = owner
75
+ self[field_prototype.name] = field
50
76
  end
51
77
  end
52
78
  end
@@ -4,19 +4,19 @@ module Spontaneous::Collections
4
4
  class PrototypeSet
5
5
  include Enumerable
6
6
 
7
- attr_reader :store
7
+ attr_reader :store, :local_order
8
8
 
9
9
  def initialize(superobject = nil, superset_name = nil)
10
10
  @superobject, @superset_name = superobject, superset_name
11
11
  @has_superset = !!(@superobject && @superobject.respond_to?(@superset_name))
12
12
  @store = {}
13
- @order = []
13
+ @local_order = []
14
14
  end
15
15
 
16
16
  def []=(name, value)
17
17
  key = name.to_sym
18
18
  @store[key] = value
19
- @order << key unless order.include?(key)
19
+ add_key(key)
20
20
  end
21
21
 
22
22
  def [](key)
@@ -28,6 +28,10 @@ module Spontaneous::Collections
28
28
  end
29
29
  end
30
30
 
31
+ def add_key(key)
32
+ local_order << key unless order.include?(key)
33
+ end
34
+
31
35
  def key?(key)
32
36
  keys.include?(key.to_sym)
33
37
  end
@@ -49,7 +53,7 @@ module Spontaneous::Collections
49
53
  end
50
54
 
51
55
  def local_first
52
- if (key = @order.first)
56
+ if (key = local_order.first)
53
57
  named(key)
54
58
  else
55
59
  superset? ? superset.local_first : nil
@@ -69,7 +73,7 @@ module Spontaneous::Collections
69
73
  end
70
74
 
71
75
  def local_values
72
- @order.map { |name| named(name) }
76
+ local_order.map { |name| named(name) }
73
77
  end
74
78
 
75
79
  def sid(schema_id)
@@ -99,26 +103,26 @@ module Spontaneous::Collections
99
103
  # set.order = [:b, :d]
100
104
  # set.order #=> [:b, :d, :a, :c]
101
105
  #
102
- def order=(new_order)
106
+ def order=(newlocal_order)
103
107
  # clear any previous custom order
104
108
  @custom_order = nil
105
- old_order = order.dup
109
+ oldlocal_order = order.dup
106
110
  order = []
107
- new_order.each do |name|
111
+ newlocal_order.each do |name|
108
112
  key = name.to_sym
109
- if old_order.include?(key)
110
- old_order.delete(key)
113
+ if oldlocal_order.include?(key)
114
+ oldlocal_order.delete(key)
111
115
  order << key
112
116
  end
113
117
  end
114
- order += old_order
118
+ order += oldlocal_order
115
119
  @custom_order = order
116
120
  end
117
121
 
118
122
 
119
123
  def order
120
124
  return @custom_order if @custom_order
121
- superset? ? (superset.order + @order) : @order
125
+ superset? ? (superset.order + local_order) : local_order
122
126
  end
123
127
 
124
128
  alias_method :names, :order
@@ -146,7 +150,7 @@ module Spontaneous::Collections
146
150
  @superset ||= @superobject.send(@superset_name) if superset?
147
151
  end
148
152
 
149
- protected
153
+
150
154
 
151
155
  def method_missing(method, *args)
152
156
  if key?(method)
@@ -155,5 +159,8 @@ module Spontaneous::Collections
155
159
  super
156
160
  end
157
161
  end
162
+
163
+ protected :local_order, :method_missing
164
+
158
165
  end # PrototypeSet
159
166
  end # Spontaneous
@@ -10,6 +10,7 @@ module Spontaneous
10
10
  QUESTION = "?".freeze
11
11
  LF = "\n".freeze
12
12
  PATH_INFO = "PATH_INFO".freeze
13
+ REQUEST_METHOD = "REQUEST_METHOD".freeze
13
14
 
14
15
  SPOT_REVISION_NUMBER = "SPOT_REVISION".freeze
15
16
  SPOT_ROOT = "SPOT_ROOT".freeze
@@ -20,5 +21,7 @@ module Spontaneous
20
21
  RE_FLATTEN = /[^\.a-z0-9-]+/.freeze
21
22
  RE_FLATTEN_REPEAT = /\-+/.freeze
22
23
  RE_FLATTEN_TRAILING = /(^\-|\-$)/.freeze
24
+
25
+ VISIBILITY_PATH_SEP = ".".freeze
23
26
  end
24
27
  end
@@ -14,10 +14,10 @@ module Spontaneous
14
14
  include Plugins::SchemaId
15
15
 
16
16
  sequel_plugin :content_table_inheritance, :type_sid
17
- sequel_plugin :serialization, :yajl, :field_store, :entry_store, :box_store
17
+ sequel_plugin :serialization, :ojson, :field_store, :entry_store, :box_store, :serialized_modifications
18
18
  sequel_plugin :instance_hooks
19
19
  sequel_plugin :skip_create_refresh
20
- sequel_plugin :timestamps, :create=>:created_at, :update=>:modified_at
20
+ sequel_plugin :timestamps, :create=>:created_at, :update_on_create => true
21
21
  sequel_plugin :identity_map
22
22
  sequel_plugin :association_dependencies
23
23
  sequel_plugin :defaults_setter
@@ -38,9 +38,10 @@ module Spontaneous
38
38
  page?
39
39
  end
40
40
 
41
- many_to_one :owner, :key => :owner_id, :class => Content, :reciprocal => :_pieces
42
- one_to_many :_pieces, :key => :owner_id, :class => Content, :reciprocal => :owner
43
- many_to_one :page, :key => :page_id, :class => Content, :reciprocal => :content
41
+ many_to_one :owner, :key => :owner_id, :class => Content, :reciprocal => :_pieces
42
+ one_to_many :_pieces, :key => :owner_id, :class => Content, :reciprocal => :owner
43
+ many_to_one :page, :key => :page_id, :class => Content, :reciprocal => :content
44
+ many_to_one :created_by, :key => :created_by_id, :class => Spontaneous::Permissions::User
44
45
 
45
46
  include Enumerable
46
47
 
@@ -56,10 +57,12 @@ module Spontaneous
56
57
  include Plugins::Serialisation
57
58
  include Plugins::Media
58
59
  include Plugins::Publishing
60
+ include Plugins::Modifications
59
61
  include Plugins::Aliases
60
62
  include Plugins::Visibility
61
63
  include Plugins::Prototypes
62
64
  include Plugins::Permissions
65
+ include Plugins::ContentGroups
63
66
 
64
67
  # marker method enabling a simple test for "cms content" vs "everything else"
65
68
  def spontaneous_content?
@@ -70,6 +73,13 @@ module Spontaneous
70
73
  false
71
74
  end
72
75
 
76
+ # Provides consistency between aliases & non-aliases
77
+ # so that a mixed list of both can be treated the same
78
+ # (for instance when ensuring uniqueness)
79
+ def target
80
+ self
81
+ end
82
+
73
83
  def page?
74
84
  false
75
85
  end
@@ -108,5 +118,12 @@ module Spontaneous
108
118
  return page.formats if page
109
119
  [:html]
110
120
  end
121
+
122
+ def log_sql(io = $stdout)
123
+ db.logger = ::Logger.new(io)
124
+ yield if block_given?
125
+ ensure
126
+ db.logger = nil
127
+ end
111
128
  end
112
129
  end
@@ -32,9 +32,9 @@ module Spontaneous
32
32
  end
33
33
 
34
34
 
35
- class UnknownFormatException < Error
36
- def initialize(unsupported_format)
37
- super("Format '#{unsupported_format}' has no matching mime type")
35
+ class UnknownOutputException < Error
36
+ def initialize(content_class, unsupported_output_name)
37
+ super("Type '#{content_class}' does not output '#{unsupported_output_name}'")
38
38
  end
39
39
  end
40
40
 
@@ -3,6 +3,18 @@
3
3
  module Spontaneous
4
4
  module Extensions
5
5
  module Array
6
+ def render_using(renderer, *args)
7
+ self.map { |e|
8
+ if e.respond_to?(:render_using)
9
+ e.render_using(renderer, *args)
10
+ elsif e.respond_to?(:render)
11
+ e.render(*args)
12
+ else
13
+ e
14
+ end
15
+ }.join
16
+ end
17
+
6
18
  def render(*args)
7
19
  self.map { |e| e.respond_to?(:render) ? e.render(*args) : e }.join
8
20
  end
@@ -0,0 +1,30 @@
1
+ # encoding: UTF-8
2
+
3
+ module Enumerable
4
+ def slice_between(&b)
5
+ Enumerator.new {|y|
6
+ first = true
7
+ buf = []
8
+ prev = nil
9
+ self.each {|elt|
10
+ if first
11
+ first = false
12
+ buf << elt
13
+ prev = elt
14
+ else
15
+ if b.call(prev, elt)
16
+ y << buf
17
+ buf = [elt]
18
+ else
19
+ buf << elt
20
+ end
21
+ prev = elt
22
+ end
23
+ }
24
+ if !buf.empty?
25
+ y << buf
26
+ end
27
+ }
28
+ end
29
+ end
30
+
@@ -2,9 +2,11 @@
2
2
 
3
3
  module Spontaneous::Extensions
4
4
  module NilClass
5
- def /(alternative)
5
+ def or(alternative)
6
6
  alternative
7
7
  end
8
+
9
+ alias_method :/, :or
8
10
  end # String
9
11
  end # Extensions
10
12
 
@@ -8,6 +8,17 @@ module Spontaneous
8
8
  File.join(self, path.to_s)
9
9
  end
10
10
 
11
+ def or(alternative)
12
+ return alternative if empty?
13
+ self
14
+ end
15
+
16
+ alias_method :'|', :or
17
+
18
+ def value(format = :html)
19
+ self
20
+ end
21
+
11
22
  HTML_ESCAPE_TABLE = {
12
23
  '&' => '&amp;',
13
24
  '<' => '&lt;',
@@ -34,6 +45,11 @@ module Spontaneous
34
45
  self.gsub(/(\\|<\/|\r\n|[\n\r"'])/) { JS_ESCAPE_MAP[$1] }
35
46
  end
36
47
 
48
+ # Makes it easier to pass either a field or a String around
49
+ # in templates
50
+ def to_html
51
+ self
52
+ end
37
53
  end
38
54
  end
39
55
  end