spontaneous 0.1.0.alpha1 → 0.2.0.alpha1

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 (413) hide show
  1. data/Gemfile +40 -35
  2. data/LICENSE +20 -0
  3. data/Rakefile +39 -42
  4. data/Readme.markdown +155 -0
  5. data/application/css/definitions.scss +3 -0
  6. data/application/css/editing.scss +9 -4
  7. data/application/css/min/565d4c25e82148acb01c45c8d675b37a08676d77.css +1 -0
  8. data/application/css/min/84dbe894ea96eafd321c30823d630817bfc4b03b.css +1 -0
  9. data/application/css/min/d1b54ff4847c613618267ca1c15658e2aee0a4e5.css +1 -0
  10. data/application/css/v2.scss +144 -50
  11. data/application/js/add_alias_dialogue.js +18 -8
  12. data/application/js/ajax.js +1 -1
  13. data/application/js/authentication.js +8 -1
  14. data/application/js/box.js +37 -7
  15. data/application/js/box_container.js +1 -1
  16. data/application/js/compatibility.js +7 -0
  17. data/application/js/content.js +7 -0
  18. data/application/js/content_area.js +4 -0
  19. data/application/js/edit_panel.js +44 -18
  20. data/application/js/editing.js +12 -0
  21. data/application/js/event_source.js +17 -0
  22. data/application/js/extensions.js +2 -0
  23. data/application/js/field_types/file_field.js +2 -1
  24. data/application/js/field_types/image_field.js +35 -48
  25. data/application/js/field_types/long_string_field.js +12 -0
  26. data/application/js/field_types/markdown_field.js +2 -5
  27. data/application/js/field_types/string_field.js +5 -1
  28. data/application/js/field_types/webvideo_field.js +15 -0
  29. data/application/js/init.js +1 -0
  30. data/application/js/location.js +30 -19
  31. data/application/js/login.js +1 -2
  32. data/application/js/min/2a0c2962537a3181fedfff5c92596ba6d3122dc9.js +3 -0
  33. data/application/js/min/4cf1c493d3379ecba5287758c61238034c0893f9.js +2 -0
  34. data/application/js/min/78ac6b99d96750bb6b9f9aad4cb9cd91cd03f391.js +3 -0
  35. data/application/js/min/c8efb9b9f7c3f6613fcebc6be60f605b6570a382.js +90 -0
  36. data/application/js/page.js +1 -0
  37. data/application/js/page_entry.js +6 -40
  38. data/application/js/preview.js +2 -3
  39. data/application/js/top_bar.js +76 -31
  40. data/application/js/upload.js +5 -2
  41. data/application/js/upload_manager.js +2 -81
  42. data/application/js/vendor/jquery-1.7.1.min.js +4 -0
  43. data/application/js/vendor/jquery-ui-1.8.16.custom.min.js +791 -0
  44. data/application/js/views.js +3 -3
  45. data/application/js/views/box_view.js +164 -83
  46. data/application/js/views/page_piece_view.js +2 -2
  47. data/application/js/views/page_view.js +46 -15
  48. data/application/js/views/piece_view.js +29 -8
  49. data/application/static/diagonal-texture.png +0 -0
  50. data/application/static/item-buttons-highlight.png +0 -0
  51. data/application/static/plus-box.png +0 -0
  52. data/application/static/plus_alt.svg +8 -0
  53. data/application/static/slot-up-arrow.png +0 -0
  54. data/application/views/{index.erubis → index.erb} +9 -5
  55. data/application/views/{login.erubis → login.erb} +14 -10
  56. data/application/views/schema_modification_error.html.erb +18 -6
  57. data/application/views/{unsupported.erubis → unsupported.erb} +0 -0
  58. data/bin/spot +15 -2
  59. data/db/migrations/20100610142136_init.rb +2 -2
  60. data/db/migrations/20101130104334_timestamps.rb +2 -2
  61. data/db/migrations/20110209152710_users_and_groups.rb +11 -11
  62. data/db/migrations/20120106171423_visibility_path.rb +19 -0
  63. data/db/migrations/20120107124541_owner_id.rb +19 -0
  64. data/docs/recipe-interface-screenshot.png +0 -0
  65. data/lib/cutaneous.rb +11 -10
  66. data/lib/cutaneous/context_helper.rb +119 -14
  67. data/lib/cutaneous/preview_context.rb +4 -3
  68. data/lib/cutaneous/preview_renderer.rb +1 -6
  69. data/lib/cutaneous/publish_context.rb +1 -0
  70. data/lib/cutaneous/{first_pass_renderer.rb → publish_renderer.rb} +2 -6
  71. data/lib/cutaneous/publish_template.rb +62 -0
  72. data/lib/cutaneous/publish_token_parser.rb +8 -0
  73. data/lib/cutaneous/renderer.rb +4 -2
  74. data/lib/cutaneous/request_context.rb +1 -0
  75. data/lib/cutaneous/{second_pass_renderer.rb → request_renderer.rb} +2 -5
  76. data/lib/cutaneous/request_template.rb +11 -0
  77. data/lib/cutaneous/request_token_parser.rb +9 -0
  78. data/lib/cutaneous/token_parser.rb +125 -0
  79. data/lib/sequel/plugins/content_table_inheritance.rb +19 -12
  80. data/lib/sequel/plugins/scoped_table_name.rb +45 -0
  81. data/lib/spontaneous.rb +123 -126
  82. data/lib/spontaneous/box.rb +127 -47
  83. data/lib/spontaneous/box_style.rb +39 -22
  84. data/lib/spontaneous/change.rb +2 -2
  85. data/lib/spontaneous/cli.rb +1 -0
  86. data/lib/spontaneous/cli/base.rb +12 -4
  87. data/lib/spontaneous/cli/console.rb +72 -0
  88. data/lib/spontaneous/cli/server.rb +36 -12
  89. data/lib/spontaneous/cli/site.rb +175 -1
  90. data/lib/spontaneous/collections/box_set.rb +19 -1
  91. data/lib/spontaneous/collections/entry_set.rb +70 -22
  92. data/lib/spontaneous/collections/field_set.rb +3 -3
  93. data/lib/spontaneous/collections/prototype_set.rb +28 -0
  94. data/lib/spontaneous/config.rb +14 -5
  95. data/lib/spontaneous/content.rb +23 -24
  96. data/lib/spontaneous/errors.rb +20 -4
  97. data/lib/spontaneous/extensions/array.rb +2 -2
  98. data/lib/spontaneous/extensions/json.rb +1 -1
  99. data/lib/spontaneous/extensions/nil.rb +13 -0
  100. data/lib/spontaneous/facet.rb +61 -7
  101. data/lib/spontaneous/field_types.rb +1 -3
  102. data/lib/spontaneous/field_types/date_field.rb +1 -0
  103. data/lib/spontaneous/field_types/field.rb +32 -15
  104. data/lib/spontaneous/field_types/image_field.rb +138 -69
  105. data/lib/spontaneous/field_types/location_field.rb +59 -0
  106. data/lib/spontaneous/field_types/long_string_field.rb +13 -0
  107. data/lib/spontaneous/field_types/markdown_field.rb +2 -1
  108. data/lib/spontaneous/field_types/string_field.rb +2 -2
  109. data/lib/spontaneous/field_types/webvideo_field.rb +255 -0
  110. data/lib/spontaneous/generators/page/inline.html.cut +1 -1
  111. data/lib/spontaneous/generators/page/page.html.cut.tt +5 -4
  112. data/lib/spontaneous/generators/page/page.rb.tt +1 -5
  113. data/lib/spontaneous/generators/site.rb +1 -0
  114. data/lib/spontaneous/generators/site/.gitignore +2 -0
  115. data/lib/spontaneous/generators/site/Gemfile.tt +3 -5
  116. data/lib/spontaneous/generators/site/config/environment.rb.tt +1 -0
  117. data/lib/spontaneous/generators/site/config/environments/development.rb.tt +3 -1
  118. data/lib/spontaneous/generators/site/config/environments/production.rb.tt +3 -1
  119. data/lib/spontaneous/generators/site/config/indexes.rb.tt +23 -0
  120. data/lib/spontaneous/generators/site/public/css/{site.css → site.scss} +0 -0
  121. data/lib/spontaneous/generators/site/schema/box.rb.tt +5 -0
  122. data/lib/spontaneous/generators/site/templates/layouts/standard.html.cut.tt +11 -5
  123. data/lib/spontaneous/image_size.rb +0 -1
  124. data/lib/spontaneous/loader.rb +335 -218
  125. data/lib/spontaneous/logger.rb +7 -2
  126. data/lib/spontaneous/media.rb +64 -59
  127. data/lib/spontaneous/media/file.rb +74 -0
  128. data/lib/spontaneous/page.rb +47 -18
  129. data/lib/spontaneous/page_piece.rb +29 -27
  130. data/lib/spontaneous/paths.rb +0 -1
  131. data/lib/spontaneous/permissions.rb +3 -21
  132. data/lib/spontaneous/permissions/user.rb +5 -1
  133. data/lib/spontaneous/permissions/user_level.rb +6 -7
  134. data/lib/spontaneous/piece.rb +12 -7
  135. data/lib/spontaneous/plugins/aliases.rb +76 -31
  136. data/lib/spontaneous/plugins/allowed_types.rb +36 -37
  137. data/lib/spontaneous/plugins/application/facets.rb +7 -10
  138. data/lib/spontaneous/plugins/application/features.rb +17 -0
  139. data/lib/spontaneous/plugins/application/paths.rb +25 -31
  140. data/lib/spontaneous/plugins/application/render.rb +1 -5
  141. data/lib/spontaneous/plugins/application/serialisation.rb +2 -0
  142. data/lib/spontaneous/plugins/application/state.rb +6 -9
  143. data/lib/spontaneous/plugins/boxes.rb +65 -40
  144. data/lib/spontaneous/plugins/controllers.rb +22 -22
  145. data/lib/spontaneous/plugins/entries.rb +149 -150
  146. data/lib/spontaneous/plugins/entry.rb +50 -35
  147. data/lib/spontaneous/plugins/field/editor_class.rb +13 -0
  148. data/lib/spontaneous/plugins/fields.rb +41 -33
  149. data/lib/spontaneous/plugins/instance_code.rb +9 -9
  150. data/lib/spontaneous/plugins/layouts.rb +31 -35
  151. data/lib/spontaneous/plugins/media.rb +31 -32
  152. data/lib/spontaneous/plugins/page/formats.rb +56 -31
  153. data/lib/spontaneous/plugins/page/request.rb +15 -9
  154. data/lib/spontaneous/plugins/page_search.rb +30 -31
  155. data/lib/spontaneous/plugins/page_tree.rb +59 -12
  156. data/lib/spontaneous/plugins/paths.rb +84 -79
  157. data/lib/spontaneous/plugins/permissions.rb +26 -28
  158. data/lib/spontaneous/plugins/prototypes.rb +42 -37
  159. data/lib/spontaneous/plugins/publishing.rb +50 -94
  160. data/lib/spontaneous/plugins/render.rb +8 -16
  161. data/lib/spontaneous/plugins/schema_hierarchy.rb +20 -21
  162. data/lib/spontaneous/plugins/schema_id.rb +33 -25
  163. data/lib/spontaneous/plugins/schema_title.rb +3 -4
  164. data/lib/spontaneous/plugins/serialisation.rb +32 -35
  165. data/lib/spontaneous/plugins/site/features.rb +32 -0
  166. data/lib/spontaneous/plugins/site/instance.rb +3 -2
  167. data/lib/spontaneous/plugins/site/level.rb +18 -0
  168. data/lib/spontaneous/plugins/site/map.rb +2 -1
  169. data/lib/spontaneous/plugins/site/publishing.rb +56 -59
  170. data/lib/spontaneous/plugins/site/revisions.rb +24 -19
  171. data/lib/spontaneous/plugins/site/schema.rb +33 -0
  172. data/lib/spontaneous/plugins/site/search.rb +43 -0
  173. data/lib/spontaneous/plugins/site/selectors.rb +35 -30
  174. data/lib/spontaneous/plugins/site/storage.rb +63 -0
  175. data/lib/spontaneous/plugins/site_map.rb +23 -25
  176. data/lib/spontaneous/plugins/styles.rb +35 -43
  177. data/lib/spontaneous/plugins/supertype.rb +3 -1
  178. data/lib/spontaneous/plugins/visibility.rb +90 -83
  179. data/lib/spontaneous/prototypes/box_prototype.rb +55 -25
  180. data/lib/spontaneous/prototypes/field_prototype.rb +66 -19
  181. data/lib/spontaneous/prototypes/style_prototype.rb +2 -2
  182. data/lib/spontaneous/publishing.rb +1 -1
  183. data/lib/spontaneous/publishing/immediate.rb +128 -49
  184. data/lib/spontaneous/publishing/simultaneous.rb +70 -0
  185. data/lib/spontaneous/rack.rb +38 -26
  186. data/lib/spontaneous/rack/around_back.rb +3 -23
  187. data/lib/spontaneous/rack/around_preview.rb +3 -8
  188. data/lib/spontaneous/rack/assets.rb +7 -6
  189. data/lib/spontaneous/rack/authentication.rb +21 -0
  190. data/lib/spontaneous/rack/back.rb +310 -331
  191. data/lib/spontaneous/rack/cacheable_file.rb +27 -0
  192. data/lib/spontaneous/rack/cookie_authentication.rb +38 -0
  193. data/lib/spontaneous/rack/css.rb +43 -0
  194. data/lib/spontaneous/rack/event_source.rb +31 -0
  195. data/lib/spontaneous/rack/front.rb +30 -8
  196. data/lib/spontaneous/rack/helpers.rb +31 -0
  197. data/lib/spontaneous/rack/media.rb +22 -21
  198. data/lib/spontaneous/rack/public.rb +2 -1
  199. data/lib/spontaneous/rack/query_authentication.rb +35 -0
  200. data/lib/spontaneous/rack/reloader.rb +6 -3
  201. data/lib/spontaneous/rack/user_helpers.rb +28 -0
  202. data/lib/spontaneous/render.rb +64 -23
  203. data/lib/spontaneous/render/context_base.rb +143 -0
  204. data/lib/spontaneous/render/format.rb +24 -19
  205. data/lib/spontaneous/render/helpers.rb +14 -0
  206. data/lib/spontaneous/render/helpers/html_helper.rb +69 -0
  207. data/lib/spontaneous/render/helpers/script_helper.rb +17 -0
  208. data/lib/spontaneous/render/helpers/stylesheet_helper.rb +16 -0
  209. data/lib/spontaneous/render/preview_context.rb +8 -0
  210. data/lib/spontaneous/render/preview_renderer.rb +6 -0
  211. data/lib/spontaneous/render/publish_context.rb +22 -0
  212. data/lib/spontaneous/render/published_renderer.rb +12 -13
  213. data/lib/spontaneous/render/publishing_renderer.rb +3 -0
  214. data/lib/spontaneous/render/render_cache.rb +26 -0
  215. data/lib/spontaneous/render/renderer.rb +5 -1
  216. data/lib/spontaneous/render/request_context.rb +8 -0
  217. data/lib/spontaneous/schema.rb +56 -24
  218. data/lib/spontaneous/schema/schema_modification.rb +2 -2
  219. data/lib/spontaneous/schema/uid.rb +22 -106
  220. data/lib/spontaneous/schema/uid_map.rb +120 -0
  221. data/lib/spontaneous/search.rb +11 -0
  222. data/lib/spontaneous/search/compound_indexer.rb +26 -0
  223. data/lib/spontaneous/search/database.rb +72 -0
  224. data/lib/spontaneous/search/field.rb +95 -0
  225. data/lib/spontaneous/search/index.rb +184 -0
  226. data/lib/spontaneous/search/results.rb +34 -0
  227. data/lib/spontaneous/server.rb +5 -1
  228. data/lib/spontaneous/site.rb +56 -16
  229. data/lib/spontaneous/storage.rb +22 -0
  230. data/lib/spontaneous/storage/backend.rb +10 -0
  231. data/lib/spontaneous/storage/cloud.rb +104 -0
  232. data/lib/spontaneous/storage/local.rb +52 -0
  233. data/lib/spontaneous/style.rb +27 -9
  234. data/lib/spontaneous/version.rb +1 -1
  235. data/spontaneous.gemspec +719 -0
  236. data/test/disabled/test_slots.rb +1 -1
  237. data/test/experimental/test_cutaneous.rb +309 -0
  238. data/test/experimental/test_features.rb +129 -0
  239. data/test/fixtures/application/views/{index.erubis → index.erb} +0 -0
  240. data/test/fixtures/back/public/css/sass_include.scss +5 -0
  241. data/test/fixtures/back/public/css/sass_template.scss +4 -0
  242. data/test/fixtures/example_application/templates/client_project.html.cut +4 -4
  243. data/test/fixtures/example_application/templates/client_project/images.html.cut +1 -1
  244. data/test/fixtures/example_application/templates/client_projects.html.cut +2 -2
  245. data/test/fixtures/example_application/templates/inline_image.html.cut +1 -1
  246. data/test/fixtures/example_application/templates/layouts/home.html.cut +7 -7
  247. data/test/fixtures/example_application/templates/layouts/info.html.cut +1 -1
  248. data/test/fixtures/example_application/templates/layouts/project.html.cut +4 -4
  249. data/test/fixtures/example_application/templates/layouts/projects.html.cut +2 -2
  250. data/test/fixtures/example_application/templates/project.html.cut +2 -2
  251. data/test/fixtures/example_application/templates/project/inline.html.cut +3 -3
  252. data/test/fixtures/example_application/templates/project_image.html.cut +1 -1
  253. data/test/fixtures/example_application/templates/text.html.cut +1 -1
  254. data/test/fixtures/fields/youtube_api_response.xml +102 -0
  255. data/test/fixtures/layouts/layouts/custom4.html.cut +0 -0
  256. data/test/fixtures/plugins/schema_plugin/public/css/plugin.css +1 -0
  257. data/test/fixtures/plugins/schema_plugin/public/js/plugin.js +1 -0
  258. data/test/fixtures/plugins/schema_plugin/public/static.html +1 -0
  259. data/test/fixtures/plugins/schema_plugin/public/subdir/image.gif +1 -0
  260. data/test/fixtures/plugins/schema_plugin/public/subdir/include1.scss +3 -0
  261. data/test/fixtures/plugins/schema_plugin/public/subdir/sass.scss +4 -0
  262. data/test/fixtures/plugins/schema_plugin/public/subdir/sass/include2.scss +4 -0
  263. data/test/fixtures/public/templates/layouts/default.html.cut +1 -1
  264. data/test/fixtures/public/templates/layouts/default.pdf.cut +1 -1
  265. data/test/fixtures/public/templates/layouts/default.rss.cut +1 -1
  266. data/test/fixtures/public/templates/layouts/dynamic.html.cut +1 -1
  267. data/test/fixtures/schema_modification/config/database.yml +0 -0
  268. data/test/fixtures/schema_modification/config/environment.rb +2 -0
  269. data/test/fixtures/schema_modification/schema/box.rb +1 -0
  270. data/test/fixtures/schema_modification/schema/custom_box.rb +1 -0
  271. data/test/fixtures/schema_modification/schema/page.rb +6 -0
  272. data/test/fixtures/schema_modification/schema/piece.rb +1 -0
  273. data/test/fixtures/search/config/database.yml +1 -0
  274. data/test/fixtures/search/config/indexes.rb +4 -0
  275. data/test/fixtures/serialisation/root_hash.yaml.erb +16 -20
  276. data/test/fixtures/storage/cloud/environment.rb +12 -0
  277. data/test/fixtures/storage/default/environment.rb +1 -0
  278. data/test/fixtures/templates/aliases/layouts/c_alias.html.cut +1 -1
  279. data/test/fixtures/templates/content/include.html.cut +1 -1
  280. data/test/fixtures/templates/content/include_dir.html.cut +1 -1
  281. data/test/fixtures/templates/content/included.epub.cut +1 -1
  282. data/test/fixtures/templates/content/included.html.cut +1 -1
  283. data/test/fixtures/templates/content/partial/included.html.cut +1 -1
  284. data/test/fixtures/templates/content/preprocess.html.cut +1 -1
  285. data/test/fixtures/templates/content/second.html.cut +1 -1
  286. data/test/fixtures/templates/content/template.epub.cut +1 -1
  287. data/test/fixtures/templates/content/template.html.cut +1 -1
  288. data/test/fixtures/templates/default_style_class.html.cut +1 -1
  289. data/test/fixtures/templates/engine/braces.html.cut +6 -0
  290. data/test/fixtures/templates/engine/multiline.html.cut +5 -0
  291. data/test/fixtures/templates/extended/grandparent.html.cut +7 -7
  292. data/test/fixtures/templates/extended/main.html.cut +5 -5
  293. data/test/fixtures/templates/extended/parent.html.cut +10 -8
  294. data/test/fixtures/templates/extended/partial.html.cut +1 -0
  295. data/test/fixtures/templates/extended/partial_with_locals.html.cut +1 -0
  296. data/test/fixtures/templates/extended/with_includes.html.cut +9 -0
  297. data/test/fixtures/templates/extended/with_includes_and_locals.html.cut +9 -0
  298. data/test/fixtures/templates/layouts/entries.html.cut +7 -7
  299. data/test/fixtures/templates/layouts/page_style.html.cut +1 -1
  300. data/test/fixtures/templates/layouts/params.html.cut +1 -1
  301. data/test/fixtures/templates/layouts/preview_render.html.cut +2 -2
  302. data/test/fixtures/templates/layouts/standard_page.html.cut +1 -1
  303. data/test/fixtures/templates/layouts/subdir_style.html.cut +1 -1
  304. data/test/fixtures/templates/layouts/template_params.html.cut +1 -1
  305. data/test/fixtures/templates/layouts/variables.html.cut +7 -0
  306. data/test/fixtures/templates/page_class/inline_style.html.cut +1 -1
  307. data/test/fixtures/templates/preview_render/variables.html.cut +1 -0
  308. data/test/fixtures/templates/publishing/templates/layouts/dynamic.html.cut +1 -0
  309. data/test/fixtures/templates/publishing/templates/layouts/dynamic.rtf.cut +1 -0
  310. data/test/fixtures/templates/publishing/templates/layouts/static.html.cut +1 -0
  311. data/test/fixtures/templates/template_class/anonymous_style.html.cut +2 -2
  312. data/test/fixtures/templates/template_class/complex_template.html.cut +4 -4
  313. data/test/fixtures/templates/template_class/complex_template.pdf.cut +4 -4
  314. data/test/fixtures/templates/template_class/default_template_style.html.cut +2 -2
  315. data/test/fixtures/templates/template_class/images_with_template.html.cut +3 -3
  316. data/test/fixtures/templates/template_class/slots_template.html.cut +3 -3
  317. data/test/fixtures/templates/template_class/slots_template.pdf.cut +3 -3
  318. data/test/fixtures/templates/template_class/this_template.epub.cut +1 -1
  319. data/test/fixtures/templates/template_class/this_template.html.cut +1 -1
  320. data/test/fixtures/templates/template_class/this_template.pdf.cut +1 -1
  321. data/test/fixtures/templates/with_default_style_class.html.cut +1 -1
  322. data/test/functional/test_application.rb +19 -15
  323. data/test/functional/test_back.rb +130 -98
  324. data/test/functional/test_front.rb +72 -28
  325. data/test/javascript/test_dom.rb +1 -1
  326. data/test/javascript/test_markdown.rb +1 -1
  327. data/test/slow/test_publishing.rb +94 -75
  328. data/test/slow/test_visibility.rb +47 -14
  329. data/test/test_helper.rb +30 -3
  330. data/test/ui/test_page_editing.rb +1 -1
  331. data/test/unit/test_alias.rb +200 -16
  332. data/test/unit/test_authentication.rb +26 -28
  333. data/test/unit/test_boxes.rb +146 -75
  334. data/test/unit/test_config.rb +42 -20
  335. data/test/unit/test_content.rb +156 -37
  336. data/test/unit/test_content_inheritance.rb +4 -2
  337. data/test/unit/test_extensions.rb +7 -1
  338. data/test/unit/test_fields.rb +558 -290
  339. data/test/{experimental → unit}/test_formats.rb +42 -3
  340. data/test/unit/test_generators.rb +3 -2
  341. data/test/unit/test_helpers.rb +54 -0
  342. data/test/unit/test_image_size.rb +1 -1
  343. data/test/unit/test_images.rb +51 -40
  344. data/test/unit/test_layouts.rb +21 -4
  345. data/test/unit/test_logger.rb +1 -1
  346. data/test/unit/test_media.rb +165 -7
  347. data/test/unit/test_page.rb +158 -27
  348. data/test/unit/test_permissions.rb +170 -187
  349. data/test/unit/test_piece.rb +27 -9
  350. data/test/unit/test_plugins.rb +153 -0
  351. data/test/unit/test_prototype_set.rb +60 -2
  352. data/test/unit/test_prototypes.rb +81 -20
  353. data/test/unit/test_render.rb +97 -9
  354. data/test/unit/test_schema.rb +167 -120
  355. data/test/unit/test_search.rb +588 -0
  356. data/test/unit/test_serialisation.rb +26 -10
  357. data/test/unit/test_site.rb +42 -25
  358. data/test/unit/test_storage.rb +88 -0
  359. data/test/unit/test_structure.rb +11 -5
  360. data/test/unit/test_styles.rb +64 -3
  361. data/test/unit/test_table_scoping.rb +76 -0
  362. data/test/unit/test_templates.rb +69 -31
  363. data/test/unit/test_type_hierarchy.rb +9 -1
  364. metadata +274 -208
  365. data/Gemfile.lock +0 -146
  366. data/application/css/min/54ee0ed3c7fac7632bd5c020d69e9a2503e0c88c.css +0 -1
  367. data/application/css/min/c256adc144e2bdd0b0539356b04eb62db01e1dc3.css +0 -1
  368. data/application/js/edit_dialogue.js +0 -137
  369. data/application/js/min/492a209de8ee955fa9c729a765377495001e11b1.js +0 -17
  370. data/application/js/min/80f684d77c940887a1d4a63e3a96102e993baa98.js +0 -88
  371. data/application/js/min/c7140ec9475e5bf868b901e0621338d7d162358b.js +0 -3
  372. data/application/js/min/f07f2bd6630ee31e1c2288ec223383d8f0658ba6.js +0 -2
  373. data/application/js/vendor/.DS_Store +0 -0
  374. data/application/js/vendor/JS.Class-2.1.5/src/command.js +0 -93
  375. data/application/js/vendor/JS.Class-2.1.5/src/comparable.js +0 -37
  376. data/application/js/vendor/JS.Class-2.1.5/src/constant_scope.js +0 -48
  377. data/application/js/vendor/JS.Class-2.1.5/src/core.js +0 -1060
  378. data/application/js/vendor/JS.Class-2.1.5/src/decorator.js +0 -50
  379. data/application/js/vendor/JS.Class-2.1.5/src/enumerable.js +0 -505
  380. data/application/js/vendor/JS.Class-2.1.5/src/forwardable.js +0 -22
  381. data/application/js/vendor/JS.Class-2.1.5/src/hash.js +0 -334
  382. data/application/js/vendor/JS.Class-2.1.5/src/linked_list.js +0 -114
  383. data/application/js/vendor/JS.Class-2.1.5/src/loader.js +0 -553
  384. data/application/js/vendor/JS.Class-2.1.5/src/method_chain.js +0 -172
  385. data/application/js/vendor/JS.Class-2.1.5/src/observable.js +0 -55
  386. data/application/js/vendor/JS.Class-2.1.5/src/package.js +0 -472
  387. data/application/js/vendor/JS.Class-2.1.5/src/proxy.js +0 -58
  388. data/application/js/vendor/JS.Class-2.1.5/src/ruby.js +0 -44
  389. data/application/js/vendor/JS.Class-2.1.5/src/set.js +0 -332
  390. data/application/js/vendor/JS.Class-2.1.5/src/stack_trace.js +0 -151
  391. data/application/js/vendor/JS.Class-2.1.5/src/state.js +0 -95
  392. data/application/js/vendor/JS.Class-2.1.5/src/stdlib.js +0 -2612
  393. data/application/js/vendor/jquery-1.4.2.min.js +0 -154
  394. data/application/js/vendor/jquery-1.4.3.min.js +0 -166
  395. data/application/js/vendor/jquery-1.5.1.min.js +0 -16
  396. data/application/js/vendor/jquery-1.5.1rc1.min.js +0 -24
  397. data/application/js/vendor/jquery-ui-1.8.6.custom.min.js +0 -265
  398. data/application/js/vendor/jquery-ui-1.8.custom.min.js +0 -106
  399. data/application/js/vendor/jquery.hotkeys-0.7.9.js +0 -248
  400. data/application/js/vendor/jquery.hotkeys-0.7.9.min.js +0 -19
  401. data/application/js/vendor/jsdiff.js +0 -169
  402. data/lib/cutaneous/first_pass_parser.rb +0 -23
  403. data/lib/cutaneous/parser_core.rb +0 -18
  404. data/lib/cutaneous/second_pass_parser.rb +0 -23
  405. data/lib/sequel/plugins/yajl_serialization.rb +0 -154
  406. data/lib/spontaneous/plugins.rb +0 -20
  407. data/lib/spontaneous/proxy_object.rb +0 -12
  408. data/lib/spontaneous/publishing/fire_and_forget.rb +0 -57
  409. data/lib/spontaneous/render/context.rb +0 -100
  410. data/spontaneous.gemspec.tmpl +0 -66
  411. data/test/experimental/test_plugins.rb +0 -64
  412. data/test/fixtures/templates/publishing/layouts/dynamic.html.cut +0 -1
  413. data/test/fixtures/templates/publishing/layouts/static.html.cut +0 -1
@@ -0,0 +1,120 @@
1
+ # encoding: UTF-8
2
+
3
+
4
+ require 'base58'
5
+
6
+ module Spontaneous::Schema
7
+ class UIDMap
8
+
9
+ def self.uid_lock
10
+ @uid_lock ||= Mutex.new
11
+ end
12
+
13
+ def self.uid_index
14
+ @uid_index ||= 0
15
+ end
16
+
17
+ def self.increment_uid_index
18
+ @uid_index = (uid_index + 1) % 0xFFFF
19
+ end
20
+
21
+ def self.get_inc
22
+ uid_lock.synchronize do
23
+ increment_uid_index
24
+ end
25
+ end
26
+
27
+ def self.generate(ref = nil)
28
+ generate58(ref)
29
+ end
30
+
31
+ def self.generate58(ref)
32
+ # reverse the time so that sequential ids are more obviously different
33
+ oid = Base58.encode((Time.now.to_f * 1000).to_i).reverse
34
+ oid << Base58.encode(get_inc).rjust(3, '0')
35
+ end
36
+
37
+ def self.generate16(ref)
38
+ oid = ''
39
+ # 4 bytes current time
40
+ oid = (Time.now.to_f * 1000).to_i.to_s(16)
41
+ # 2 bytes inc
42
+ oid << get_inc.to_s(16).rjust(4, '0')
43
+ end
44
+
45
+ include Enumerable
46
+
47
+ def initialize
48
+ @instance_lock = Mutex.new
49
+ @instances = {}
50
+ end
51
+
52
+ def load(id, reference)
53
+ @instance_lock.synchronize do
54
+ unless instance = @instances[id]
55
+ instance = UID.new(self, id, reference)
56
+ # check to make sure that the uid is valid first
57
+ # this ensures that UIDs are not created before their owners
58
+ # have uids
59
+ if instance.valid?
60
+ @instances[id] = instance
61
+ else
62
+ instance = nil
63
+ end
64
+ end
65
+ instance
66
+ end
67
+ end
68
+
69
+ def create(reference)
70
+ unless instance = @instances.values.detect { |i| i.reference == reference }
71
+ instance = load(self.class.generate(reference), reference)
72
+ end
73
+ instance
74
+ end
75
+
76
+ def existing_references
77
+ @instances.values.map { |i| i.reference }
78
+ end
79
+
80
+ def create_for(obj)
81
+ id = create(obj.schema_name)
82
+ obj.update_schema_id(id) if obj.respond_to?(:update_schema_id)
83
+ end
84
+
85
+ def destroy(uid)
86
+ @instance_lock.synchronize do
87
+ @instances.delete(uid.to_s)
88
+ uid.after_destroy
89
+ end
90
+ end
91
+
92
+ def clear!
93
+ @instances = {}
94
+ end
95
+
96
+ def [](id)
97
+ return id if UID === id
98
+ return nil if id.blank?
99
+ @instances[id]
100
+ end
101
+
102
+ def get_id(reference)
103
+ self.find { |uid| uid.reference == reference }
104
+ end
105
+
106
+ def each
107
+ uids = @instances.map { |id, instance| instance }
108
+ if block_given?
109
+ uids.each { |instance| yield(instance) }
110
+ else
111
+ uids.each
112
+ end
113
+ end
114
+
115
+
116
+ def export
117
+ Hash[ @instances.map { |id, ref| [id, ref.reference] } ]
118
+ end
119
+ end # UIDMap
120
+ end
@@ -0,0 +1,11 @@
1
+ # encoding: UTF-8
2
+
3
+ module Spontaneous
4
+ module Search
5
+ autoload :Index, 'spontaneous/search/index'
6
+ autoload :Field, 'spontaneous/search/field'
7
+ autoload :Database, 'spontaneous/search/database'
8
+ autoload :Results, 'spontaneous/search/results'
9
+ autoload :CompoundIndexer, 'spontaneous/search/compound_indexer'
10
+ end
11
+ end
@@ -0,0 +1,26 @@
1
+ # encoding: UTF-8
2
+
3
+
4
+ module Spontaneous::Search
5
+ class CompoundIndexer
6
+ def initialize(revision, indexes)
7
+ @revision, @indexes, @dbs = revision, indexes, indexes.map { |index| index.create_db(revision) }
8
+ end
9
+
10
+ def length
11
+ @indexes.length
12
+ end
13
+ alias_method :count, :length
14
+ alias_method :size, :length
15
+
16
+ def add(page)
17
+ @dbs.each { |db| db << page }
18
+ end
19
+
20
+ alias_method :<<, :add
21
+
22
+ def close
23
+ @dbs.each { |db| db.close }
24
+ end
25
+ end # CompoundIndexer
26
+ end
@@ -0,0 +1,72 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'xapian-fu'
4
+
5
+ module Spontaneous::Search
6
+ class Database
7
+ def self.create(index, revision)
8
+ db = self.new(index, revision)
9
+ db.create
10
+ db
11
+ end
12
+
13
+ def initialize(index, revision)
14
+ @index, @revision, @database = index, revision, nil
15
+ end
16
+
17
+ def create
18
+ FileUtils.mkdir_p(directory)
19
+ @database = XapianFu::XapianDb.new(xapian_options.merge({
20
+ :create => true,
21
+ :overwrite => true
22
+ }))
23
+ end
24
+
25
+ def xapian_options
26
+ options = { :dir => directory,
27
+ :language => @index.language,
28
+ :fields => @index.fields,
29
+ :spelling => true }
30
+ options[:stemmer] = @index.stemmer unless @index.stemmer.nil?
31
+ options[:stopper] = @index.stopper unless @index.stopper.nil?
32
+ options
33
+ end
34
+
35
+ def database
36
+ @database ||= open_database
37
+ end
38
+
39
+ def open_database
40
+ XapianFu::XapianDb.new(xapian_options)
41
+ end
42
+
43
+ def add(page)
44
+ if @index.include?(page)
45
+ database << @index.indexable_content(page)
46
+ end
47
+ end
48
+
49
+ def close
50
+ database.flush
51
+ end
52
+
53
+ def search(query, options = {})
54
+ xapian_results = database.search(query, options)
55
+ autocorrect = options.delete(:autocorrect)
56
+ corrected_query = xapian_results.corrected_query
57
+ # don't know if this is the right way to deal with the corrected query suggestion
58
+ # but I would prefer that any searches act more like google and return a set of
59
+ # results for a spelling correction if none have been found with the current query
60
+ if autocorrect and xapian_results.empty? and !corrected_query.blank?
61
+ xapian_results = database.search(corrected_query, options)
62
+ end
63
+ Results.new(xapian_results, corrected_query)
64
+ end
65
+
66
+ alias_method :<<, :add
67
+
68
+ def directory
69
+ S::Site.revision_dir(@revision) / "indexes" / @index.name
70
+ end
71
+ end # Database
72
+ end
@@ -0,0 +1,95 @@
1
+ # encoding: UTF-8
2
+
3
+ module Spontaneous::Search
4
+ class Field
5
+ attr_reader :prototype, :options
6
+
7
+ def initialize(prototype, options)
8
+ @prototype = prototype
9
+ @options = options
10
+ end
11
+
12
+ def in_index?(index)
13
+ indexes.any? { |opts| opts[:index] == index }
14
+ end
15
+
16
+ def index_id(index)
17
+ opts = options_for_index(index)
18
+ opts[:group] || prototype.schema_id.to_s
19
+ end
20
+
21
+ def options_for_index(index)
22
+ indexes.detect { |opts| opts[:index] == index }
23
+ end
24
+
25
+ WEIGHTINGS = {
26
+ :normal => 1,
27
+ :high => 4,
28
+ :higher => 8,
29
+ :highest => 16
30
+ }.freeze unless defined?(WEIGHTINGS)
31
+
32
+ def field_definition(index)
33
+ defn = {:type => String, :store => true, :weight => 1, :index => true}
34
+ opts = options_for_index(index)
35
+ case opts[:weight]
36
+ when :store
37
+ defn.merge!({
38
+ :index => false,
39
+ :store => true
40
+ })
41
+ when Fixnum
42
+ defn.merge!({
43
+ :weight => opts[:weight]
44
+ })
45
+ when Symbol
46
+ defn.merge!({
47
+ :weight => WEIGHTINGS[opts[:weight]] || 1
48
+ })
49
+ end
50
+ defn
51
+ end
52
+
53
+ def indexes
54
+ @indexes ||= parse_indexes(options)
55
+ end
56
+
57
+ # convert the options passed to :index in a field definition to a list of
58
+ # options. Each entry contains the index to which it pertains and then
59
+ # the options that should be applied to this field within that index
60
+ def parse_indexes(opts)
61
+ all_indexes = S::Site.indexes.values
62
+ case opts
63
+ when true
64
+ all_indexes.map { |index| default_index_options(index) }
65
+ when Symbol
66
+ index = find_index(opts)
67
+ [default_index_options(index)]
68
+ when Hash
69
+ if (index_name = opts[:name])
70
+ [ opts.merge(:index => find_index(index_name)) ]
71
+ else
72
+ all_indexes.map { |index| default_index_options(index).merge(opts) }
73
+ end
74
+ when Array
75
+ opts.map { |o| parse_indexes(o) }.flatten
76
+ else
77
+ []
78
+ end
79
+ end
80
+
81
+ def default_index_options(index)
82
+ index_options(index)
83
+ end
84
+
85
+ def index_options(index, weight = 1, group = nil)
86
+ {:name => index.name, :index => index, :weight => weight, :group => group}
87
+ end
88
+
89
+ def find_index(name)
90
+ index = S::Site.indexes[name]
91
+ logger.warn("Invalid index :#{opts} for field #{@prototype.owner}.#{@prototype.name}") unless index
92
+ index
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,184 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'xapian-fu'
4
+
5
+ module Spontaneous::Search
6
+ class Index
7
+
8
+ attr_reader :name, :search_types
9
+
10
+ def initialize(name, &definition)
11
+ @name = name
12
+ @search_types = base_search_types
13
+ @include_pages = nil
14
+ @exclude_pages = nil
15
+ @stemmer = @stopper = nil
16
+ self.instance_eval(&definition) if definition
17
+ end
18
+
19
+ # Index DSL methods
20
+ def include_pages(*page_list)
21
+ @include_pages = page_list
22
+ end
23
+
24
+ def exclude_pages(*page_list)
25
+ @exclude_pages = page_list
26
+ end
27
+
28
+ def include_types(*types)
29
+ @search_types = resolve_type_list(types)
30
+ end
31
+
32
+ def exclude_types(*types)
33
+ @search_types -= resolve_type_list(types)
34
+ end
35
+ # end Index DSL methods
36
+
37
+ def create_db(revision)
38
+ Database.create(self, revision)
39
+ end
40
+
41
+ def search(query, options = {})
42
+ database.search(query, options)
43
+ end
44
+
45
+ def database(revision = Spontaneous::Site.published_revision)
46
+ Database.new(self, revision)
47
+ end
48
+
49
+ def language(set_language = nil)
50
+ @language = set_language unless set_language.nil?
51
+ @language ||= :english
52
+ end
53
+
54
+ def stemmer(set_stemmer = nil)
55
+ @stemmer = set_stemmer unless set_stemmer.nil?
56
+ @stemmer
57
+ end
58
+
59
+ def stopper(set_stopper = nil)
60
+ @stopper = set_stopper unless set_stopper.nil?
61
+ @stopper
62
+ end
63
+
64
+ # Extract all indexable content from a page. Values are grouped across fields
65
+ # or across field index groups
66
+ def indexable_content(page)
67
+ values = Hash.new { |h, k| h[k] = [] }
68
+ # not sure that I need the include? test here as page.content only returns Pieces
69
+ # and I'm not sure that there is a particular need to exclude Pieces from indexes
70
+ pieces = [page].concat(page.content).select { |content| include?(content) }
71
+ pieces += page.boxes.select { |box| include?(box) }
72
+ pieces.each do |content|
73
+ content.fields.each do |field|
74
+ prototype = field.prototype
75
+ values[prototype.index_id(self)] << field.indexable_value if prototype.in_index?(self)
76
+ end
77
+ end
78
+ result = Hash[ values.map { |id, values| [id, values.join("\n")] } ]
79
+ result[:id] = page.id
80
+ result
81
+ end
82
+
83
+ def fields
84
+ field_lists = Hash.new { |h, k| h[k] = [] }
85
+ # collect all the definitions for a particular field or group
86
+ all_types.select { |t| include_type?(t) }.each do |type|
87
+ type.field_prototypes.each do |prototype|
88
+ if prototype.in_index?(self)
89
+ field_lists[prototype.index_id(self)] << prototype.options_for_index(self)
90
+ end
91
+ end
92
+ end
93
+ # then aggregate/merge them
94
+ fields = {}
95
+ field_lists.each do |id, definitions|
96
+ if definitions.length == 1
97
+ fields[id] = definitions[0]
98
+ else
99
+ # if *any* of the definitions require indexing, then index
100
+ index = definitions.map { |d| d[:index] }.any? { |i| i != false }
101
+ fields[id] = {
102
+ :type => String,
103
+ :weight => definitions.map { |d| d[:weight] }.max,
104
+ :store => true,
105
+ :index => index
106
+ }
107
+ fields[id].delete(:weight) unless index
108
+ end
109
+ end
110
+ fields
111
+ end
112
+
113
+ def include?(content)
114
+ include_type?(content.class) and include_page?(content.page)
115
+ end
116
+
117
+ protected
118
+
119
+ def include_type?(type)
120
+ search_types.include?(type)
121
+ end
122
+
123
+ def include_page?(page)
124
+ return true unless page.page?
125
+ unless @exclude_pages.nil?
126
+ rejected = @exclude_pages.any? { |selector| match_page(selector, page) }
127
+ return false if rejected
128
+ end
129
+ unless @include_pages.nil?
130
+ included = @include_pages.any? { |selector| match_page(selector, page) }
131
+ return false if !included
132
+ end
133
+ true
134
+ end
135
+
136
+ # TODO: move this into a generic page query language class
137
+ def match_page(selector, page)
138
+ case selector
139
+ when Fixnum, /\A\d+\z/
140
+ page.id == selector.to_i
141
+ when /\A#(.+)\z/
142
+ page.uid == $1
143
+ when /\A\//
144
+ page.path == selector
145
+ when /\A(>=|>)\s+(.+)\z/
146
+ rule, root = $1, S::Site[$2]
147
+ root.send(rule, page)
148
+ else
149
+ false
150
+ end
151
+ end
152
+
153
+ def resolve_page_list(pages)
154
+ pages.map { |p| S::Site[p] }
155
+ end
156
+
157
+ def base_search_types
158
+ all_types
159
+ end
160
+
161
+ def resolve_type_list(types)
162
+ types.map { |klass| find_type(klass) }.flatten
163
+ end
164
+
165
+ def find_type(type_definition)
166
+ return type_definition if type_definition.is_a?(Class)
167
+ type_definition = type_definition.to_s if Symbol === type_definition
168
+ if type_definition.is_a?(String)
169
+ scope, base = type_definition.split(/\s+/).map { |s| s.strip }
170
+ return scope.constantize if base.nil?
171
+ base_type = base.constantize
172
+ all_types.select { |klass| base_type.send(scope, klass) }
173
+ end
174
+ end
175
+
176
+ def all_types
177
+ S.schema.classes
178
+ end
179
+
180
+ def all_page_types
181
+ S.schema.classes.select { |klass| klass.page? }
182
+ end
183
+ end # Index
184
+ end # Spontaneous