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,588 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path('../../test_helper', __FILE__)
4
+
5
+ class SearchTest < MiniTest::Spec
6
+
7
+ # search should be defined by DSL
8
+ # DSL should
9
+ # - Allow naming of index
10
+ # - Allow restricting of the content by hierarchy
11
+ # - (Including/Excluding) Page & children (>=)
12
+ # - (Including/Excluding) Children of page (>)
13
+ # - Allow restricting of indexed content by type
14
+ # - (Including/Excluding) Specific Page types
15
+ # - (Including/Excluding) Page types & subclasses (>=)
16
+ # - (Including/Excluding) Subclasses of type (>)
17
+ #
18
+ # Fields should be included in indexes
19
+ # - Default is to add field to all indexes
20
+ # - Should be able to include on a per index basis
21
+ # - Should be able to set the weight factor globally & per-index
22
+ # - Should be able to partition fields into groups so that in search query you can specify that query is in particular group of fields
23
+ #
24
+ # - Indexing is done by page
25
+
26
+
27
+
28
+ def self.startup
29
+ # make sure that S::Piece & S::Page are removed from the schema
30
+ setup_site
31
+ *ids = S::Page.schema_id, S::Piece.schema_id
32
+ Object.const_set(:Site, Class.new(S::Site))
33
+ end
34
+
35
+ def self.shutdown
36
+ Object.send(:remove_const, :Site) rescue nil
37
+ end
38
+
39
+ def setup
40
+ @site = setup_site
41
+ end
42
+
43
+ def teardown
44
+ teardown_site
45
+ end
46
+
47
+ context "Search" do
48
+ setup do
49
+ Content.delete
50
+
51
+
52
+ class ::Piece < S::Piece; end
53
+ class ::Page < S::Page; end
54
+ b = ::Page.box :pages
55
+ # instantiate box instance class to it gets added to schema
56
+ ::Page.boxes.pages.instance_class.schema_id
57
+
58
+ class ::PageClass1 < ::Page; end
59
+ class ::PageClass2 < ::Page; end
60
+ class ::PageClass3 < ::PageClass1; end
61
+ class ::PageClass4 < ::PageClass2; end
62
+ class ::PageClass5 < ::PageClass3; end
63
+ class ::PageClass6 < ::PageClass5; end
64
+
65
+ class ::PieceClass1 < ::Piece; end
66
+ class ::PieceClass2 < ::Piece; end
67
+ class ::PieceClass3 < ::Piece; end
68
+
69
+ @all_page_classes = [::Page, ::PageClass1, ::PageClass2, ::PageClass3, ::PageClass4, ::PageClass5, ::PageClass6]
70
+ @all_piece_classes = [::Piece, ::PieceClass1, ::PieceClass2, ::PieceClass3]
71
+ @all_box_classes = [ ::Page::PagesBox ]
72
+ @all_classes = @all_page_classes + @all_piece_classes + @all_box_classes
73
+
74
+ @root0 = ::Page.create(:uid => "root")
75
+ @page1 = ::PageClass1.create(:slug => "page1", :uid => "page1")
76
+ @root0.pages << @page1
77
+ @page2 = ::PageClass2.create(:slug => "page2", :uid => "page2")
78
+ @root0.pages << @page2
79
+ @page3 = ::PageClass3.create(:slug => "page3", :uid => "page3")
80
+ @root0.pages << @page3
81
+ @page4 = ::PageClass4.create(:slug => "page4", :uid => "page4")
82
+ @root0.pages << @page4
83
+ @page5 = ::PageClass5.create(:slug => "page5", :uid => "page5")
84
+ @root0.pages << @page5
85
+ @page6 = ::PageClass6.create(:slug => "page6", :uid => "page6")
86
+ @root0.pages << @page6
87
+
88
+ @page7 = ::PageClass1.create(:slug => "page7", :uid => "page7")
89
+ @page1.pages << @page7
90
+ @page8 = ::PageClass6.create(:slug => "page8", :uid => "page8")
91
+ @page1.pages << @page8
92
+
93
+ @page9 = ::PageClass1.create(:slug => "page9", :uid => "page9")
94
+ @page8.pages << @page9
95
+ @page10 = ::PageClass2.create(:slug => "page10", :uid => "page10")
96
+ @page8.pages << @page10
97
+ @page11 = ::PageClass3.create(:slug => "page11", :uid => "page11")
98
+ @page8.pages << @page11
99
+ @page12 = ::PageClass4.create(:slug => "page12", :uid => "page12")
100
+ @page8.pages << @page12
101
+
102
+ @all_pages = [@root0, @page1, @page2, @page3, @page4, @page5, @page6, @page7, @page8, @page9, @page10, @page11, @page12]
103
+ @all_pages.each { |page| page.save; page.reload }
104
+ end
105
+
106
+ teardown do
107
+ (@all_classes.map { |k| k.name.to_sym }).each { |klass|
108
+ Object.send(:remove_const, klass) rescue nil
109
+ } rescue nil
110
+ Content.delete
111
+ end
112
+
113
+ context "indexes" do
114
+
115
+ should "be retrievable by name" do
116
+ index = S::Site.index :arthur
117
+ S::Site.indexes[:arthur].must_be_instance_of Spontaneous::Search::Index
118
+ S::Site.indexes[:arthur].name.should == :arthur
119
+ S::Site.indexes[:arthur].should == index
120
+ end
121
+
122
+ should "default to indexing all content classes" do
123
+ index = S::Site.index :all
124
+ assert_same_elements (@all_classes), index.search_types
125
+ end
126
+
127
+ should "allow restriction to particular classes" do
128
+ index = S::Site.index :all do
129
+ include_types ::PageClass1, "PageClass2", :PageClass3
130
+ end
131
+ assert_same_elements [::PageClass1, ::PageClass2, ::PageClass3], index.search_types
132
+ end
133
+
134
+ should "allow restriction to a class & its subclasses" do
135
+ index = S::Site.index :all do
136
+ include_types ">= PageClass1"
137
+ end
138
+ assert_same_elements [::PageClass1, ::PageClass3, ::PageClass5, ::PageClass6], index.search_types
139
+ end
140
+
141
+ should "allow restriction to a class's subclasses" do
142
+ index = S::Site.index :all do
143
+ include_types "> PageClass1"
144
+ end
145
+ assert_same_elements [::PageClass3, ::PageClass5, ::PageClass6], index.search_types
146
+ end
147
+
148
+ should "allow removal of particular classes" do
149
+ index = S::Site.index :all do
150
+ exclude_types ::PageClass1, "PageClass2"
151
+ end
152
+ assert_same_elements (@all_classes - [PageClass1, PageClass2]), index.search_types
153
+ end
154
+
155
+ should "allow removal of a class and its subclasses" do
156
+ index = S::Site.index :all do
157
+ exclude_types ">= PageClass1", PieceClass1
158
+ end
159
+ assert_same_elements (@all_classes - [::PageClass1, ::PageClass3, ::PageClass5, ::PageClass6, PieceClass1]), index.search_types
160
+ end
161
+
162
+ should "allow removal of a class's subclasses" do
163
+ index = S::Site.index :all do
164
+ exclude_types "> PageClass1"
165
+ end
166
+ assert_same_elements (@all_classes - [::PageClass3, ::PageClass5, ::PageClass6]), index.search_types
167
+ end
168
+
169
+ should "default to including all content" do
170
+ index = S::Site.index :all
171
+ @all_pages.each do |page|
172
+ index.include?(page).should be_true
173
+ end
174
+ end
175
+
176
+ should "allow restriction to a set of specific pages" do
177
+ id = @root0.id
178
+ path = @page8.path
179
+ index = S::Site.index :all do
180
+ include_pages id, "#page11", path
181
+ end
182
+
183
+ @all_pages.map{ |page| index.include?(page) }.should ==
184
+ [true,false,false,false,false,false,false,false,true,false,false,true,false]
185
+ end
186
+
187
+ should "allow restriction to a page and its children" do
188
+ index = S::Site.index :all do
189
+ include_pages ">= #page8"
190
+ end
191
+
192
+ @all_pages.map{ |page| index.include?(page) }.should ==
193
+ [false,false,false,false,false,false,false,false,true,true,true,true,true]
194
+ end
195
+
196
+ should "allow restriction to a page's children" do
197
+ index = S::Site.index :all do
198
+ include_pages "> #page8"
199
+ end
200
+
201
+ @all_pages.map{ |page| index.include?(page) }.should ==
202
+ [false,false,false,false,false,false,false,false,false,true,true,true,true]
203
+ end
204
+
205
+ should "allow removal of specific pages" do
206
+ index = S::Site.index :all do
207
+ exclude_pages "#page8", "/page1"
208
+ end
209
+
210
+ @all_pages.map{ |page| index.include?(page) }.should ==
211
+ [true,false,true,true,true,true,true,true,false,true,true,true,true]
212
+ end
213
+
214
+ should "allow removal of a page and its children" do
215
+ index = S::Site.index :all do
216
+ exclude_pages "/page1", ">= #page8"
217
+ end
218
+
219
+ @all_pages.map{ |page| index.include?(page) }.should ==
220
+ [true,false,true,true,true,true,true,true,false,false,false,false,false]
221
+ end
222
+
223
+ should "allow removal of a page's children" do
224
+ index = S::Site.index :all do
225
+ exclude_pages "/page1", "> #page8"
226
+ end
227
+
228
+ @all_pages.map{ |page| index.include?(page) }.should ==
229
+ [true,false,true,true,true,true,true,true,true,false,false,false,false]
230
+ end
231
+
232
+ should "allow multiple, mixed, page restrictions" do
233
+ index = S::Site.index :all do
234
+ include_pages "#page1", "> #page8"
235
+ end
236
+
237
+ @all_pages.map{ |page| index.include?(page) }.should ==
238
+ [false,true,false,false,false,false,false,false,false,true,true,true,true]
239
+ end
240
+
241
+ should "allow combining of class and page restrictions" do
242
+ index = S::Site.index :all do
243
+ exclude_types PageClass3, PageClass4
244
+ include_pages "#page1", "> #page8"
245
+ exclude_pages "#page10"
246
+ end
247
+ @all_pages.map{ |page| index.include?(page) }.should ==
248
+ [false,true,false,false,false,false,false,false,false,true,false,false,false]
249
+ end
250
+ end
251
+
252
+ context "Fields definitions" do
253
+ # Inclusion of field in indexes.
254
+ # Default is not to include field
255
+ # By adding the following clause:
256
+ #
257
+ # field :title, :index => true
258
+ #
259
+ # you include the :title field in all indexes with a search weight of 1. this is equivalent to the following:
260
+ #
261
+ # field :title, :index => { :name => :*, :weight => 1, :group => nil }
262
+ #
263
+ # If you only want to include this field in a specific index, then you do the following:
264
+ #
265
+ # field :title, :index => :tags
266
+ #
267
+ # this is equivalent to
268
+ #
269
+ # field :title, :index => { :name => :tags, :weight => 1, :group => nil }
270
+ #
271
+ # or if you want to include it into more than one index:
272
+ #
273
+ # field :title, :index => [:tags, :content]
274
+ #
275
+ # this is equivalent to
276
+ #
277
+ # field :title, :index => [
278
+ # { :name => :tags, :weight => 1, :group => nil },
279
+ # { :name => :content, :weight => 1, :group => nil }]
280
+ #
281
+ # Groups:
282
+ #
283
+ # Normally field values are grouped by content types. Indexes are generated from a page by iterating through
284
+ # all it's pieces and creating a single aggregate value for each field of each type found
285
+ #
286
+ # Groups are a way of joining disparate fields from different types into a single, addressable/searchable
287
+ # index
288
+ #
289
+ # weight:
290
+ #
291
+ # weight defines how much priority is given to a field. I.e. if your search term occurs in a field
292
+ # with a high weight value then it will apear higher in the results list than in a page where the
293
+ # term appears in a lower weight field
294
+ #
295
+ # :store = 0 : store but don't index (makes value available to results lister without loading page from db)
296
+ # :normal = 1 : default weight
297
+ # :high = 2 : high weight
298
+ # :higher = 4 : higher weight
299
+ # :highest = 8 : higest
300
+ #
301
+ # actual weight are powers of 10: 10, 100, 10000, 100000000 (unless this is different from Ferret)
302
+ #
303
+ #
304
+ setup do
305
+ @index1 = S::Site.index(:one)
306
+ @index2 = S::Site.index(:two)
307
+ @index3 = S::Site.index(:three) do
308
+ include_types PageClass1
309
+ end
310
+ end
311
+
312
+ teardown do
313
+ end
314
+
315
+ should "be included in all indexes if :index is set to true" do
316
+ prototype_a = PageClass1.field :a, :index => true
317
+ prototype_a.in_index?(@index1).should be_true
318
+ prototype_a.in_index?(@index2).should be_true
319
+ prototype_a.in_index?(@index3).should be_true
320
+ end
321
+
322
+ should "be included in indexes referenced by name" do
323
+ prototype_a = PageClass1.field :a, :index => [:one, :two]
324
+ prototype_a.in_index?(@index1).should be_true
325
+ prototype_a.in_index?(@index2).should be_true
326
+ prototype_a.in_index?(@index3).should be_false
327
+ end
328
+
329
+ should "be included in indexes referenced as hash" do
330
+ prototype_a = PageClass1.field :a, :index => {:name => :two}
331
+ prototype_a.in_index?(@index1).should be_false
332
+ prototype_a.in_index?(@index2).should be_true
333
+ prototype_a.in_index?(@index3).should be_false
334
+ end
335
+
336
+ should "be included in indexes listed in hash" do
337
+ prototype_a = PageClass1.field :a, :index => [{:name => :one}, {:name => :two}]
338
+ prototype_a.in_index?(@index1).should be_true
339
+ prototype_a.in_index?(@index2).should be_true
340
+ prototype_a.in_index?(@index3).should be_false
341
+ end
342
+
343
+ should "return the field's schema id as its index name by default" do
344
+ prototype_a = PageClass1.field :a, :index => [{:name => :one}, {:name => :two, :group => :a}]
345
+ prototype_a.index_id(@index1).should == prototype_a.schema_id.to_s
346
+ prototype_a.index_id(@index2).should == :a
347
+ end
348
+
349
+ should "produce a field list in a xapian-fu compatible format" do
350
+ a = PageClass1.field :a, :index => [{:name => :one, :weight => :store},
351
+ {:name => :two, :group => :a, :weight => 2}]
352
+ b = PageClass2.field :b, :index => :one
353
+ c = ::Piece.field :c, :index => [{:name => :one, :weight => 4}, {:name => :two, :group => :a}]
354
+ d = ::Piece.field :d, :index => :three
355
+ e = ::PageClass1.field :e, :index => :three
356
+ f = ::PageClass2.field :f, :index => :three
357
+ g = ::Piece.field :g, :index => {:weight => :highest}
358
+
359
+ h = ::PageClass1.boxes.pages.instance_class.field :h, :index => :two
360
+
361
+ S::Site.indexes[:one].fields.should == {
362
+ a.schema_id.to_s => { :type => String, :store => true, :index => false},
363
+ b.schema_id.to_s => { :type => String, :store => true, :weight => 1, :index => true},
364
+ c.schema_id.to_s => { :type => String, :store => true, :weight => 4, :index => true},
365
+ g.schema_id.to_s => { :type => String, :store => true, :weight => 16, :index => true}
366
+ }
367
+
368
+ S::Site.indexes[:two].fields.should == {
369
+ :a => { :type => String, :store => true, :weight => 2, :index => true},
370
+ g.schema_id.to_s => { :type => String, :store => true, :weight => 16, :index => true},
371
+ h.schema_id.to_s => { :type => String, :store => true, :weight => 1, :index => true}
372
+ }
373
+
374
+ S::Site.indexes[:three].fields.should == {
375
+ e.schema_id.to_s => { :type => String, :store => true, :weight => 1, :index => true}
376
+ }
377
+ end
378
+ end
379
+
380
+ context "Indexes" do
381
+ setup do
382
+ @revision = 99
383
+
384
+ @index1 = S::Site.index :one do
385
+ exclude_types PageClass3
386
+ end
387
+ @index2 = S::Site.index :two
388
+
389
+ @a = PageClass1.field :a, :index => true
390
+ @b = PageClass2.field :b, :index => true
391
+ @c = PageClass3.field :c, :index => true
392
+ @d = PageClass4.field :d, :index => true
393
+ @e = PageClass5.field :e, :index => true
394
+ @f = PageClass6.field :f, :index => true
395
+ @g = PieceClass1.field :g, :index => true
396
+ @h = PieceClass2.field :h, :index => true
397
+ @i = PieceClass3.field :i, :index => {:group => :i}
398
+ @j = PieceClass3.field :j, :index => {:group => :i}
399
+ @k = PieceClass3.field :k
400
+
401
+ @l = ::PageClass1.boxes.pages.instance_class.field :l, :index => true
402
+
403
+ @page1.a = "a value 1"
404
+ @page1.pages.first.a = "a value 2"
405
+ @page1.pages.l = "l value 1"
406
+
407
+ @piece1 = PieceClass1.new(:g => "g value 1")
408
+ @page1.pages << @piece1
409
+ @piece2 = PieceClass1.new(:g => "g value 2")
410
+ @page1.pages << @piece2
411
+ @piece3 = PieceClass1.new(:g => "g value 3")
412
+ @page1.pages << @piece3
413
+ @piece4 = PieceClass2.new(:h => "h value 1")
414
+ @page1.pages << @piece4
415
+ @piece5 = PieceClass2.new(:h => "h value 2")
416
+ @page1.pages << @piece5
417
+ @piece6 = PieceClass3.new(:i => "i value 1", :j => "j value 1", :k => "k value 1")
418
+ @page1.pages << @piece6
419
+ @piece7 = PieceClass3.new(:i => "i value 2", :j => "j value 2", :k => "k value 2")
420
+ @page1.pages << @piece7
421
+
422
+ @page2.b = "b value 1"
423
+ @page3.c = "c value 1"
424
+ @page1.save
425
+ end
426
+
427
+ teardown do
428
+ end
429
+
430
+ should "correctly extract content from pages" do
431
+ @page1.a.expects(:indexable_value).returns("(a value 1)")
432
+ @index1.indexable_content(@page1).should == {
433
+ :id => @page1.id,
434
+ @a.schema_id.to_s => "(a value 1)",
435
+ @g.schema_id.to_s => "g value 1\ng value 2\ng value 3",
436
+ @h.schema_id.to_s => "h value 1\nh value 2",
437
+ :i => "i value 1\nj value 1\ni value 2\nj value 2",
438
+ @l.schema_id.to_s => "l value 1",
439
+ }
440
+ end
441
+
442
+ should "only include specified pieces" do
443
+ index = S::Site.index :four do
444
+ include_types PageClass1, PieceClass1
445
+ end
446
+
447
+ index.indexable_content(@page1).should == {
448
+ :id => @page1.id,
449
+ @a.schema_id.to_s => "a value 1",
450
+ @g.schema_id.to_s => "g value 1\ng value 2\ng value 3",
451
+ }
452
+ end
453
+
454
+ should "create database in the right directory" do
455
+ db_path = @site.revision_dir(@revision) / 'indexes' / 'one'
456
+ Site.stubs(:published_revision).returns(@revision)
457
+ mset = mock()
458
+ mset.stubs(:matches).returns([])
459
+ xapian = mock()
460
+ xapian.expects(:<<).with(@index1.indexable_content(@page1))
461
+ xapian.expects(:search).with('"value 2"', {}).returns(XapianFu::ResultSet.new(:mset => mset))
462
+ xapian.expects(:flush)
463
+
464
+ XapianFu::XapianDb.expects(:new).with({
465
+ :dir => db_path,
466
+ :create => true,
467
+ :overwrite => true,
468
+ :language => :english,
469
+ :fields => @index1.fields,
470
+ :spelling => true
471
+ }).returns(xapian)
472
+
473
+ db = @index1.create_db(@revision)
474
+ assert File.directory?(db_path)
475
+ db << @page1
476
+ db << @page3
477
+ db.close
478
+ db.search('"value 2"')
479
+ FileUtils.rm_r(db_path)
480
+ end
481
+
482
+ should "pass on index configuration to the xapian db" do
483
+ db_path = @site.revision_dir(@revision) / 'indexes' / 'name'
484
+
485
+ index = Site.index :name do
486
+ language :italian
487
+ end
488
+
489
+ XapianFu::XapianDb.expects(:new).with({
490
+ :dir => db_path,
491
+ :create => true,
492
+ :overwrite => true,
493
+ :language => :italian,
494
+ :fields => index.fields,
495
+ :spelling => true
496
+ })
497
+
498
+ db = index.create_db(@revision)
499
+
500
+ index = Site.index :name do
501
+ language :french
502
+ stopper false
503
+ stemmer false
504
+ end
505
+
506
+ XapianFu::XapianDb.expects(:new).with({
507
+ :dir => db_path,
508
+ :create => true,
509
+ :overwrite => true,
510
+ :language => :french,
511
+ :stemmer => false,
512
+ :stopper => false,
513
+ :fields => index.fields,
514
+ :spelling => true
515
+ })
516
+
517
+ db = index.create_db(@revision)
518
+
519
+ FileUtils.rm_r(db_path)
520
+ end
521
+
522
+ should "return (reasonable) results to searches" do
523
+ db_path = @site.revision_dir(@revision) / 'indexes' / 'one'
524
+ Site.stubs(:published_revision).returns(@revision)
525
+ db = @index1.create_db(@revision)
526
+ db << @page1
527
+ db << @page2
528
+ db << @page3
529
+ db.close
530
+
531
+ results = @index1.search('+valeu', :limit => 1, :autocorrect => true)
532
+ results.must_be_instance_of S::Search::Results
533
+ results.each do |result|
534
+ result.class.should < S::Page
535
+ end
536
+
537
+ results.corrected_query.should == '+value'
538
+ results.current_page.should == 1
539
+ results.per_page.should == 1
540
+ results.total_pages.should == 2
541
+ results.next_page.should == 2
542
+ results.offset.should == 0
543
+ results.previous_page.should == nil
544
+ results.total_entries.should == 2
545
+
546
+ results = @index1.search('valeu', :limit => 1, :autocorrect => false)
547
+ results.corrected_query.should == 'value'
548
+ results.total_entries.should == 0
549
+
550
+ results = @index1.search('value', :limit => 1)
551
+ results.corrected_query.should == ''
552
+ results.total_entries.should == 2
553
+
554
+ FileUtils.rm_r(db_path)
555
+ end
556
+
557
+ should "provide a convenient way to add documents to multiple indexes" do
558
+ db1 = mock()
559
+ db2 = mock()
560
+ @index1.expects(:create_db).with(@revision).returns(db1)
561
+ @index2.expects(:create_db).with(@revision).returns(db2)
562
+ db1.expects(:<<).with(@page1)
563
+ db2.expects(:<<).with(@page1)
564
+ db1.expects(:close)
565
+ db2.expects(:close)
566
+ S::Site.indexer(@revision) do |indexer|
567
+ indexer.length.should == 2
568
+ indexer << @page1
569
+ end
570
+ end
571
+ end
572
+
573
+ context "initialization" do
574
+ setup do
575
+ FileUtils.cp_r(File.expand_path("../../fixtures/search/config", __FILE__), @site.root)
576
+ end
577
+
578
+ should "load the config/indexes.rb file" do
579
+ @site.expects(:connect_to_database!)
580
+ @site.initialize!
581
+ index = @site.indexes[:fast]
582
+ index.must_be_instance_of S::Search::Index
583
+ index.name.should == :fast
584
+ index.search_types.should == [PageClass1, PageClass2, PageClass3]
585
+ end
586
+ end
587
+ end
588
+ end