spontaneous 0.1.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 (556) hide show
  1. data/Gemfile +49 -0
  2. data/Gemfile.lock +146 -0
  3. data/LICENSE +0 -0
  4. data/README +0 -0
  5. data/Rakefile +284 -0
  6. data/Readme.markdown +7 -0
  7. data/application/css/add_alias_dialogue.scss +27 -0
  8. data/application/css/definitions.scss +249 -0
  9. data/application/css/developer.scss +9 -0
  10. data/application/css/editing.scss +649 -0
  11. data/application/css/login.scss +91 -0
  12. data/application/css/min/54ee0ed3c7fac7632bd5c020d69e9a2503e0c88c.css +1 -0
  13. data/application/css/min/c256adc144e2bdd0b0539356b04eb62db01e1dc3.css +1 -0
  14. data/application/css/popover.scss +335 -0
  15. data/application/css/schema_error.scss +90 -0
  16. data/application/css/spontaneous.scss +111 -0
  17. data/application/css/unsupported.scss +16 -0
  18. data/application/css/v2.scss +1606 -0
  19. data/application/css/variables.scss +80 -0
  20. data/application/js/add_alias_dialogue.js +59 -0
  21. data/application/js/add_home_dialogue.js +59 -0
  22. data/application/js/ajax.js +99 -0
  23. data/application/js/authentication.js +22 -0
  24. data/application/js/box.js +104 -0
  25. data/application/js/box_container.js +82 -0
  26. data/application/js/compatibility.js +132 -0
  27. data/application/js/conflicted_field_dialogue.js +92 -0
  28. data/application/js/content.js +224 -0
  29. data/application/js/content_area.js +44 -0
  30. data/application/js/dialogue.js +196 -0
  31. data/application/js/dom.js +71 -0
  32. data/application/js/edit_dialogue.js +137 -0
  33. data/application/js/edit_panel.js +232 -0
  34. data/application/js/editing.js +42 -0
  35. data/application/js/entry.js +13 -0
  36. data/application/js/extensions.js +104 -0
  37. data/application/js/field.js +4 -0
  38. data/application/js/field_preview.js +55 -0
  39. data/application/js/field_types/date_field.js +16 -0
  40. data/application/js/field_types/file_field.js +71 -0
  41. data/application/js/field_types/image_field.js +358 -0
  42. data/application/js/field_types/markdown_field.js +656 -0
  43. data/application/js/field_types/string_field.js +185 -0
  44. data/application/js/image.js +72 -0
  45. data/application/js/init.js +34 -0
  46. data/application/js/load.js +4 -0
  47. data/application/js/location.js +157 -0
  48. data/application/js/login.js +53 -0
  49. data/application/js/min/492a209de8ee955fa9c729a765377495001e11b1.js +17 -0
  50. data/application/js/min/80f684d77c940887a1d4a63e3a96102e993baa98.js +88 -0
  51. data/application/js/min/b8abf302a824c35385ff517b34111e1710ff3b37.js +2 -0
  52. data/application/js/min/c7140ec9475e5bf868b901e0621338d7d162358b.js +3 -0
  53. data/application/js/min/f07f2bd6630ee31e1c2288ec223383d8f0658ba6.js +2 -0
  54. data/application/js/page.js +43 -0
  55. data/application/js/page_browser.js +147 -0
  56. data/application/js/page_entry.js +47 -0
  57. data/application/js/popover.js +99 -0
  58. data/application/js/popover_view.js +56 -0
  59. data/application/js/preview.js +64 -0
  60. data/application/js/progress.js +358 -0
  61. data/application/js/properties.js +90 -0
  62. data/application/js/publish.js +187 -0
  63. data/application/js/require.js +129 -0
  64. data/application/js/sharded_upload.js +206 -0
  65. data/application/js/side_bar.js +30 -0
  66. data/application/js/spontaneous.js +6 -0
  67. data/application/js/state.js +64 -0
  68. data/application/js/status_bar.js +47 -0
  69. data/application/js/top_bar.js +368 -0
  70. data/application/js/types.js +98 -0
  71. data/application/js/upload.js +88 -0
  72. data/application/js/upload_manager.js +319 -0
  73. data/application/js/user.js +37 -0
  74. data/application/js/vendor/.DS_Store +0 -0
  75. data/application/js/vendor/JS.Class-2.1.5/CHANGELOG +283 -0
  76. data/application/js/vendor/JS.Class-2.1.5/MIT-LICENSE +30 -0
  77. data/application/js/vendor/JS.Class-2.1.5/README +30 -0
  78. data/application/js/vendor/JS.Class-2.1.5/min/command.js +1 -0
  79. data/application/js/vendor/JS.Class-2.1.5/min/comparable.js +1 -0
  80. data/application/js/vendor/JS.Class-2.1.5/min/constant_scope.js +1 -0
  81. data/application/js/vendor/JS.Class-2.1.5/min/core.js +1 -0
  82. data/application/js/vendor/JS.Class-2.1.5/min/decorator.js +1 -0
  83. data/application/js/vendor/JS.Class-2.1.5/min/enumerable.js +1 -0
  84. data/application/js/vendor/JS.Class-2.1.5/min/forwardable.js +1 -0
  85. data/application/js/vendor/JS.Class-2.1.5/min/hash.js +1 -0
  86. data/application/js/vendor/JS.Class-2.1.5/min/linked_list.js +1 -0
  87. data/application/js/vendor/JS.Class-2.1.5/min/loader.js +1 -0
  88. data/application/js/vendor/JS.Class-2.1.5/min/method_chain.js +1 -0
  89. data/application/js/vendor/JS.Class-2.1.5/min/observable.js +1 -0
  90. data/application/js/vendor/JS.Class-2.1.5/min/package.js +1 -0
  91. data/application/js/vendor/JS.Class-2.1.5/min/proxy.js +1 -0
  92. data/application/js/vendor/JS.Class-2.1.5/min/ruby.js +1 -0
  93. data/application/js/vendor/JS.Class-2.1.5/min/set.js +1 -0
  94. data/application/js/vendor/JS.Class-2.1.5/min/stack_trace.js +1 -0
  95. data/application/js/vendor/JS.Class-2.1.5/min/state.js +1 -0
  96. data/application/js/vendor/JS.Class-2.1.5/min/stdlib.js +16 -0
  97. data/application/js/vendor/JS.Class-2.1.5/src/command.js +93 -0
  98. data/application/js/vendor/JS.Class-2.1.5/src/comparable.js +37 -0
  99. data/application/js/vendor/JS.Class-2.1.5/src/constant_scope.js +48 -0
  100. data/application/js/vendor/JS.Class-2.1.5/src/core.js +1060 -0
  101. data/application/js/vendor/JS.Class-2.1.5/src/decorator.js +50 -0
  102. data/application/js/vendor/JS.Class-2.1.5/src/enumerable.js +505 -0
  103. data/application/js/vendor/JS.Class-2.1.5/src/forwardable.js +22 -0
  104. data/application/js/vendor/JS.Class-2.1.5/src/hash.js +334 -0
  105. data/application/js/vendor/JS.Class-2.1.5/src/linked_list.js +114 -0
  106. data/application/js/vendor/JS.Class-2.1.5/src/loader.js +553 -0
  107. data/application/js/vendor/JS.Class-2.1.5/src/method_chain.js +172 -0
  108. data/application/js/vendor/JS.Class-2.1.5/src/observable.js +55 -0
  109. data/application/js/vendor/JS.Class-2.1.5/src/package.js +472 -0
  110. data/application/js/vendor/JS.Class-2.1.5/src/proxy.js +58 -0
  111. data/application/js/vendor/JS.Class-2.1.5/src/ruby.js +44 -0
  112. data/application/js/vendor/JS.Class-2.1.5/src/set.js +332 -0
  113. data/application/js/vendor/JS.Class-2.1.5/src/stack_trace.js +151 -0
  114. data/application/js/vendor/JS.Class-2.1.5/src/state.js +95 -0
  115. data/application/js/vendor/JS.Class-2.1.5/src/stdlib.js +2612 -0
  116. data/application/js/vendor/crypto-2.3.0-crypto.js +160 -0
  117. data/application/js/vendor/crypto-2.3.0-sha1.js +91 -0
  118. data/application/js/vendor/diff_match_patch.js +2153 -0
  119. data/application/js/vendor/jquery-1.4.2.min.js +154 -0
  120. data/application/js/vendor/jquery-1.4.3.min.js +166 -0
  121. data/application/js/vendor/jquery-1.5.1.min.js +16 -0
  122. data/application/js/vendor/jquery-1.5.1rc1.min.js +24 -0
  123. data/application/js/vendor/jquery-1.6.2.min.js +18 -0
  124. data/application/js/vendor/jquery-ui-1.8.6.custom.min.js +265 -0
  125. data/application/js/vendor/jquery-ui-1.8.9.custom.min.js +415 -0
  126. data/application/js/vendor/jquery-ui-1.8.custom.min.js +106 -0
  127. data/application/js/vendor/jquery.hotkeys-0.7.9.js +248 -0
  128. data/application/js/vendor/jquery.hotkeys-0.7.9.min.js +19 -0
  129. data/application/js/vendor/jsdiff.js +169 -0
  130. data/application/js/views/box_view.js +229 -0
  131. data/application/js/views/page_piece_view.js +45 -0
  132. data/application/js/views/page_view.js +238 -0
  133. data/application/js/views/piece_view.js +178 -0
  134. data/application/js/views.js +110 -0
  135. data/application/static/editing-0-noise.png +0 -0
  136. data/application/static/editing-1-noise.png +0 -0
  137. data/application/static/editing-texture-1.png +0 -0
  138. data/application/static/editing-texture.png +0 -0
  139. data/application/static/editing-toolbar-shadow-bottom.png +0 -0
  140. data/application/static/editing-toolbar-shadow-top.png +0 -0
  141. data/application/static/favicon.ico +0 -0
  142. data/application/static/inner-glow.png +0 -0
  143. data/application/static/item-buttons.png +0 -0
  144. data/application/static/location-arrow.png +0 -0
  145. data/application/static/logo-400px-transparent.png +0 -0
  146. data/application/static/missing.png +0 -0
  147. data/application/static/orange-down-arrow.png +0 -0
  148. data/application/static/page-browser-next.png +0 -0
  149. data/application/static/paper-texture-dark.png +0 -0
  150. data/application/static/px.gif +0 -0
  151. data/application/static/select-arrow-root.png +0 -0
  152. data/application/static/select-arrow.png +0 -0
  153. data/application/static/slot-down-arrow.png +0 -0
  154. data/application/static/splash.png +0 -0
  155. data/application/static/spontaneous.png +0 -0
  156. data/application/static/spot.png +0 -0
  157. data/application/static/spot.svg +40 -0
  158. data/application/static/texture.png +0 -0
  159. data/application/views/index.erubis +46 -0
  160. data/application/views/login.erubis +69 -0
  161. data/application/views/schema_modification_error.html.erb +61 -0
  162. data/application/views/unsupported.erubis +23 -0
  163. data/bin/limit-upload +5 -0
  164. data/bin/spot +10 -0
  165. data/bin/unlimit-upload +3 -0
  166. data/config/nginx.conf +60 -0
  167. data/db/migrations/20100610142136_init.rb +66 -0
  168. data/db/migrations/20101130104334_timestamps.rb +44 -0
  169. data/db/migrations/20101202113205_site_publishing_flags.rb +12 -0
  170. data/db/migrations/20101206124543_aliases.rb +16 -0
  171. data/db/migrations/20110201133550_visibility.rb +27 -0
  172. data/db/migrations/20110209152710_users_and_groups.rb +58 -0
  173. data/db/migrations/20110215133910_boxes.rb +25 -0
  174. data/db/migrations/20110521114145_remove_slots_and_entries.rb +21 -0
  175. data/db/migrations/20110604192145_rename_schema_id_columns.rb +22 -0
  176. data/db/migrations/20110805141925_rename_site_to_state.rb +11 -0
  177. data/lib/cutaneous/context_helper.rb +82 -0
  178. data/lib/cutaneous/first_pass_parser.rb +23 -0
  179. data/lib/cutaneous/first_pass_renderer.rb +18 -0
  180. data/lib/cutaneous/parser_core.rb +18 -0
  181. data/lib/cutaneous/preview_context.rb +31 -0
  182. data/lib/cutaneous/preview_renderer.rb +15 -0
  183. data/lib/cutaneous/publish_context.rb +9 -0
  184. data/lib/cutaneous/renderer.rb +122 -0
  185. data/lib/cutaneous/request_context.rb +8 -0
  186. data/lib/cutaneous/second_pass_parser.rb +23 -0
  187. data/lib/cutaneous/second_pass_renderer.rb +18 -0
  188. data/lib/cutaneous.rb +47 -0
  189. data/lib/sequel/plugins/content_table_inheritance.rb +196 -0
  190. data/lib/sequel/plugins/yajl_serialization.rb +154 -0
  191. data/lib/spontaneous/application/feature.rb +9 -0
  192. data/lib/spontaneous/application/plugin.rb +13 -0
  193. data/lib/spontaneous/application.rb +8 -0
  194. data/lib/spontaneous/box.rb +232 -0
  195. data/lib/spontaneous/box_style.rb +64 -0
  196. data/lib/spontaneous/change.rb +107 -0
  197. data/lib/spontaneous/cli/adapter.rb +13 -0
  198. data/lib/spontaneous/cli/base.rb +184 -0
  199. data/lib/spontaneous/cli/console.rb +0 -0
  200. data/lib/spontaneous/cli/media.rb +13 -0
  201. data/lib/spontaneous/cli/server.rb +50 -0
  202. data/lib/spontaneous/cli/site.rb +46 -0
  203. data/lib/spontaneous/cli/sync.rb +42 -0
  204. data/lib/spontaneous/cli/tasks.rb +9 -0
  205. data/lib/spontaneous/cli.rb +83 -0
  206. data/lib/spontaneous/collections/box_set.rb +56 -0
  207. data/lib/spontaneous/collections/change_set.rb +43 -0
  208. data/lib/spontaneous/collections/entry_set.rb +83 -0
  209. data/lib/spontaneous/collections/field_set.rb +53 -0
  210. data/lib/spontaneous/collections/prototype_set.rb +131 -0
  211. data/lib/spontaneous/collections/style_set.rb +13 -0
  212. data/lib/spontaneous/config.rb +156 -0
  213. data/lib/spontaneous/constants.rb +24 -0
  214. data/lib/spontaneous/content.rb +113 -0
  215. data/lib/spontaneous/content_query.rb +17 -0
  216. data/lib/spontaneous/errors.rb +48 -0
  217. data/lib/spontaneous/extensions/array.rb +18 -0
  218. data/lib/spontaneous/extensions/class.rb +17 -0
  219. data/lib/spontaneous/extensions/hash.rb +18 -0
  220. data/lib/spontaneous/extensions/json.rb +26 -0
  221. data/lib/spontaneous/extensions/kernel.rb +7 -0
  222. data/lib/spontaneous/extensions/object.rb +30 -0
  223. data/lib/spontaneous/extensions/object_space.rb +12 -0
  224. data/lib/spontaneous/extensions/string.rb +44 -0
  225. data/lib/spontaneous/facet.rb +47 -0
  226. data/lib/spontaneous/field_types/date_field.rb +12 -0
  227. data/lib/spontaneous/field_types/field.rb +252 -0
  228. data/lib/spontaneous/field_types/image_field.rb +329 -0
  229. data/lib/spontaneous/field_types/markdown_field.rb +37 -0
  230. data/lib/spontaneous/field_types/string_field.rb +14 -0
  231. data/lib/spontaneous/field_types.rb +40 -0
  232. data/lib/spontaneous/generators/page/inline.html.cut +1 -0
  233. data/lib/spontaneous/generators/page/page.html.cut.tt +4 -0
  234. data/lib/spontaneous/generators/page/page.rb.tt +9 -0
  235. data/lib/spontaneous/generators/page.rb +38 -0
  236. data/lib/spontaneous/generators/site/.gitignore +4 -0
  237. data/lib/spontaneous/generators/site/Gemfile.tt +31 -0
  238. data/lib/spontaneous/generators/site/Rakefile.tt +6 -0
  239. data/lib/spontaneous/generators/site/config/back.ru +7 -0
  240. data/lib/spontaneous/generators/site/config/boot.rb +19 -0
  241. data/lib/spontaneous/generators/site/config/database.yml.tt +21 -0
  242. data/lib/spontaneous/generators/site/config/deploy.rb.tt +0 -0
  243. data/lib/spontaneous/generators/site/config/environment.rb.tt +8 -0
  244. data/lib/spontaneous/generators/site/config/environments/development.rb.tt +15 -0
  245. data/lib/spontaneous/generators/site/config/environments/production.rb.tt +5 -0
  246. data/lib/spontaneous/generators/site/config/front.ru +8 -0
  247. data/lib/spontaneous/generators/site/config/user_levels.yml +22 -0
  248. data/lib/spontaneous/generators/site/lib/site.rb.tt +4 -0
  249. data/lib/spontaneous/generators/site/lib/tasks/site.rake.tt +8 -0
  250. data/lib/spontaneous/generators/site/public/css/site.css +0 -0
  251. data/lib/spontaneous/generators/site/public/favicon.ico +0 -0
  252. data/lib/spontaneous/generators/site/public/js/.empty_directory +0 -0
  253. data/lib/spontaneous/generators/site/public/js/site.js +0 -0
  254. data/lib/spontaneous/generators/site/public/robots.txt +0 -0
  255. data/lib/spontaneous/generators/site/schema/.map +1 -0
  256. data/lib/spontaneous/generators/site/schema/page.rb.tt +8 -0
  257. data/lib/spontaneous/generators/site/schema/piece.rb.tt +4 -0
  258. data/lib/spontaneous/generators/site/templates/layouts/standard.html.cut.tt +13 -0
  259. data/lib/spontaneous/generators/site.rb +77 -0
  260. data/lib/spontaneous/generators.rb +23 -0
  261. data/lib/spontaneous/image_size.rb +117 -0
  262. data/lib/spontaneous/json.rb +33 -0
  263. data/lib/spontaneous/layout.rb +15 -0
  264. data/lib/spontaneous/loader.rb +280 -0
  265. data/lib/spontaneous/logger.rb +369 -0
  266. data/lib/spontaneous/media.rb +84 -0
  267. data/lib/spontaneous/page.rb +92 -0
  268. data/lib/spontaneous/page_controller.rb +18 -0
  269. data/lib/spontaneous/page_piece.rb +77 -0
  270. data/lib/spontaneous/paths.rb +30 -0
  271. data/lib/spontaneous/permissions/access_group.rb +50 -0
  272. data/lib/spontaneous/permissions/access_key.rb +35 -0
  273. data/lib/spontaneous/permissions/user.rb +167 -0
  274. data/lib/spontaneous/permissions/user_level.rb +177 -0
  275. data/lib/spontaneous/permissions.rb +55 -0
  276. data/lib/spontaneous/piece.rb +30 -0
  277. data/lib/spontaneous/plugins/aliases.rb +128 -0
  278. data/lib/spontaneous/plugins/allowed_types.rb +173 -0
  279. data/lib/spontaneous/plugins/application/facets.rb +25 -0
  280. data/lib/spontaneous/plugins/application/paths.rb +137 -0
  281. data/lib/spontaneous/plugins/application/render.rb +29 -0
  282. data/lib/spontaneous/plugins/application/serialisation.rb +16 -0
  283. data/lib/spontaneous/plugins/application/state.rb +86 -0
  284. data/lib/spontaneous/plugins/boxes.rb +84 -0
  285. data/lib/spontaneous/plugins/controllers.rb +52 -0
  286. data/lib/spontaneous/plugins/entries.rb +193 -0
  287. data/lib/spontaneous/plugins/entry.rb +51 -0
  288. data/lib/spontaneous/plugins/fields.rb +103 -0
  289. data/lib/spontaneous/plugins/instance_code.rb +18 -0
  290. data/lib/spontaneous/plugins/layouts.rb +87 -0
  291. data/lib/spontaneous/plugins/media.rb +41 -0
  292. data/lib/spontaneous/plugins/page/formats.rb +67 -0
  293. data/lib/spontaneous/plugins/page/request.rb +89 -0
  294. data/lib/spontaneous/plugins/page_search.rb +64 -0
  295. data/lib/spontaneous/plugins/page_tree.rb +25 -0
  296. data/lib/spontaneous/plugins/paths.rb +125 -0
  297. data/lib/spontaneous/plugins/permissions.rb +63 -0
  298. data/lib/spontaneous/plugins/prototypes.rb +84 -0
  299. data/lib/spontaneous/plugins/publishing.rb +255 -0
  300. data/lib/spontaneous/plugins/render.rb +24 -0
  301. data/lib/spontaneous/plugins/schema_hierarchy.rb +76 -0
  302. data/lib/spontaneous/plugins/schema_id.rb +60 -0
  303. data/lib/spontaneous/plugins/schema_title.rb +33 -0
  304. data/lib/spontaneous/plugins/serialisation.rb +67 -0
  305. data/lib/spontaneous/plugins/site/instance.rb +22 -0
  306. data/lib/spontaneous/plugins/site/map.rb +19 -0
  307. data/lib/spontaneous/plugins/site/publishing.rb +74 -0
  308. data/lib/spontaneous/plugins/site/revisions.rb +28 -0
  309. data/lib/spontaneous/plugins/site/selectors.rb +41 -0
  310. data/lib/spontaneous/plugins/site_map.rb +34 -0
  311. data/lib/spontaneous/plugins/styles.rb +119 -0
  312. data/lib/spontaneous/plugins/supertype.rb +11 -0
  313. data/lib/spontaneous/plugins/visibility.rb +151 -0
  314. data/lib/spontaneous/plugins.rb +20 -0
  315. data/lib/spontaneous/prototypes/box_prototype.rb +168 -0
  316. data/lib/spontaneous/prototypes/field_prototype.rb +112 -0
  317. data/lib/spontaneous/prototypes/layout_prototype.rb +17 -0
  318. data/lib/spontaneous/prototypes/style_prototype.rb +42 -0
  319. data/lib/spontaneous/proxy_object.rb +12 -0
  320. data/lib/spontaneous/publishing/fire_and_forget.rb +57 -0
  321. data/lib/spontaneous/publishing/immediate.rb +197 -0
  322. data/lib/spontaneous/publishing/threaded.rb +25 -0
  323. data/lib/spontaneous/publishing.rb +10 -0
  324. data/lib/spontaneous/rack/around_back.rb +44 -0
  325. data/lib/spontaneous/rack/around_front.rb +29 -0
  326. data/lib/spontaneous/rack/around_preview.rb +26 -0
  327. data/lib/spontaneous/rack/assets.rb +98 -0
  328. data/lib/spontaneous/rack/back.rb +729 -0
  329. data/lib/spontaneous/rack/front.rb +41 -0
  330. data/lib/spontaneous/rack/http.rb +18 -0
  331. data/lib/spontaneous/rack/media.rb +29 -0
  332. data/lib/spontaneous/rack/public.rb +232 -0
  333. data/lib/spontaneous/rack/reloader.rb +42 -0
  334. data/lib/spontaneous/rack/static.rb +25 -0
  335. data/lib/spontaneous/rack.rb +55 -0
  336. data/lib/spontaneous/render/context.rb +100 -0
  337. data/lib/spontaneous/render/development_renderer.rb +14 -0
  338. data/lib/spontaneous/render/engine.rb +19 -0
  339. data/lib/spontaneous/render/format/html.rb +5 -0
  340. data/lib/spontaneous/render/format.rb +70 -0
  341. data/lib/spontaneous/render/preview_renderer.rb +18 -0
  342. data/lib/spontaneous/render/published_renderer.rb +54 -0
  343. data/lib/spontaneous/render/publishing_renderer.rb +13 -0
  344. data/lib/spontaneous/render/renderer.rb +46 -0
  345. data/lib/spontaneous/render.rb +173 -0
  346. data/lib/spontaneous/revision.rb +7 -0
  347. data/lib/spontaneous/schema/schema_modification.rb +260 -0
  348. data/lib/spontaneous/schema/uid.rb +221 -0
  349. data/lib/spontaneous/schema.rb +295 -0
  350. data/lib/spontaneous/server.rb +65 -0
  351. data/lib/spontaneous/site.rb +87 -0
  352. data/lib/spontaneous/state.rb +53 -0
  353. data/lib/spontaneous/style.rb +144 -0
  354. data/lib/spontaneous/tasks/database.rake +9 -0
  355. data/lib/spontaneous/tasks.rb +5 -0
  356. data/lib/spontaneous/version.rb +6 -0
  357. data/lib/spontaneous.rb +179 -0
  358. data/spontaneous.gemspec.tmpl +66 -0
  359. data/test/disabled/test_slots.rb +287 -0
  360. data/test/experimental/test_formats.rb +92 -0
  361. data/test/experimental/test_plugins.rb +64 -0
  362. data/test/fixtures/application/css/test.less +5 -0
  363. data/test/fixtures/application/js/test.js +1 -0
  364. data/test/fixtures/application/static/favicon.ico +1 -0
  365. data/test/fixtures/application/static/test.html +1 -0
  366. data/test/fixtures/application/views/index.erubis +1 -0
  367. data/test/fixtures/back/public/test.html +1 -0
  368. data/test/fixtures/back/templates/layouts/standard.html.cut +1 -0
  369. data/test/fixtures/config/config/environment.rb +4 -0
  370. data/test/fixtures/config/config/environments/development.rb +13 -0
  371. data/test/fixtures/config/config/environments/production.rb +22 -0
  372. data/test/fixtures/config/config/environments/staging.rb +2 -0
  373. data/test/fixtures/example_application/Gemfile +6 -0
  374. data/test/fixtures/example_application/Gemfile.lock +76 -0
  375. data/test/fixtures/example_application/Rakefile +6 -0
  376. data/test/fixtures/example_application/config/back.rb +15 -0
  377. data/test/fixtures/example_application/config/back.ru +8 -0
  378. data/test/fixtures/example_application/config/back.yml +8 -0
  379. data/test/fixtures/example_application/config/boot.rb +16 -0
  380. data/test/fixtures/example_application/config/database.yml +24 -0
  381. data/test/fixtures/example_application/config/environment.rb +4 -0
  382. data/test/fixtures/example_application/config/environments/development.rb +16 -0
  383. data/test/fixtures/example_application/config/environments/production.rb +21 -0
  384. data/test/fixtures/example_application/config/environments/staging.rb +1 -0
  385. data/test/fixtures/example_application/config/front.rb +8 -0
  386. data/test/fixtures/example_application/config/front.ru +8 -0
  387. data/test/fixtures/example_application/config/front.yml +8 -0
  388. data/test/fixtures/example_application/config/schema.yml +48 -0
  389. data/test/fixtures/example_application/config/unicorn.rb +1 -0
  390. data/test/fixtures/example_application/config/user_levels.yml +19 -0
  391. data/test/fixtures/example_application/public/css/test.css +0 -0
  392. data/test/fixtures/example_application/public/favicon.ico +1 -0
  393. data/test/fixtures/example_application/public/js/test.js +0 -0
  394. data/test/fixtures/example_application/public/test.html +1 -0
  395. data/test/fixtures/example_application/schema/client_project.rb +18 -0
  396. data/test/fixtures/example_application/schema/client_projects.rb +8 -0
  397. data/test/fixtures/example_application/schema/home_page.rb +22 -0
  398. data/test/fixtures/example_application/schema/info_page.rb +13 -0
  399. data/test/fixtures/example_application/schema/inline_image.rb +11 -0
  400. data/test/fixtures/example_application/schema/page.rb +4 -0
  401. data/test/fixtures/example_application/schema/piece.rb +3 -0
  402. data/test/fixtures/example_application/schema/project.rb +21 -0
  403. data/test/fixtures/example_application/schema/project_image.rb +18 -0
  404. data/test/fixtures/example_application/schema/projects_page.rb +12 -0
  405. data/test/fixtures/example_application/schema/text.rb +8 -0
  406. data/test/fixtures/example_application/templates/client_project/images.html.cut +1 -0
  407. data/test/fixtures/example_application/templates/client_project.html.cut +4 -0
  408. data/test/fixtures/example_application/templates/client_projects.html.cut +6 -0
  409. data/test/fixtures/example_application/templates/info_page/inline.html.cut +0 -0
  410. data/test/fixtures/example_application/templates/inline_image.html.cut +1 -0
  411. data/test/fixtures/example_application/templates/layouts/home.html.cut +15 -0
  412. data/test/fixtures/example_application/templates/layouts/info.html.cut +3 -0
  413. data/test/fixtures/example_application/templates/layouts/project.html.cut +13 -0
  414. data/test/fixtures/example_application/templates/layouts/projects.html.cut +11 -0
  415. data/test/fixtures/example_application/templates/layouts/standard.html.cut +0 -0
  416. data/test/fixtures/example_application/templates/project/inline.html.cut +5 -0
  417. data/test/fixtures/example_application/templates/project.html.cut +5 -0
  418. data/test/fixtures/example_application/templates/project_image.html.cut +1 -0
  419. data/test/fixtures/example_application/templates/text.html.cut +1 -0
  420. data/test/fixtures/images/rose.greyscale.jpg +0 -0
  421. data/test/fixtures/images/rose.jpg +0 -0
  422. data/test/fixtures/images/size.gif +0 -0
  423. data/test/fixtures/images/size.jpg +0 -0
  424. data/test/fixtures/images/size.png24 +0 -0
  425. data/test/fixtures/images/size.png8 +0 -0
  426. data/test/fixtures/layouts/layouts/custom1.html.cut +1 -0
  427. data/test/fixtures/layouts/layouts/custom1.pdf.cut +0 -0
  428. data/test/fixtures/layouts/layouts/custom1.xml.cut +0 -0
  429. data/test/fixtures/layouts/layouts/custom2.html.cut +1 -0
  430. data/test/fixtures/layouts/layouts/custom3.html.cut +0 -0
  431. data/test/fixtures/layouts/layouts/standard.html.cut +1 -0
  432. data/test/fixtures/media/101/003/rose.jpg +0 -0
  433. data/test/fixtures/permissions/config/user_levels.yml +9 -0
  434. data/test/fixtures/permissions/media/image.jpg +0 -0
  435. data/test/fixtures/plugins/schema_plugin/init.rb +1 -0
  436. data/test/fixtures/plugins/schema_plugin/schema/external.rb +5 -0
  437. data/test/fixtures/plugins/schema_plugin/templates/external.html.cut +1 -0
  438. data/test/fixtures/plugins/schema_plugin/templates/from_plugin.html.cut +0 -0
  439. data/test/fixtures/plugins/schema_plugin/templates/layouts/from_plugin.html.cut +0 -0
  440. data/test/fixtures/public/templates/layouts/default.html.cut +1 -0
  441. data/test/fixtures/public/templates/layouts/default.pdf.cut +1 -0
  442. data/test/fixtures/public/templates/layouts/default.rss.cut +1 -0
  443. data/test/fixtures/public/templates/layouts/dynamic.html.cut +1 -0
  444. data/test/fixtures/public/templates/layouts/standard.html.cut +0 -0
  445. data/test/fixtures/schema/before.yml +24 -0
  446. data/test/fixtures/schema/resolvable.yml +12 -0
  447. data/test/fixtures/schema/schema.yml +7 -0
  448. data/test/fixtures/serialisation/class_hash.yaml.erb +53 -0
  449. data/test/fixtures/serialisation/root_hash.yaml.erb +184 -0
  450. data/test/fixtures/sharding/rose.jpg +0 -0
  451. data/test/fixtures/sharding/xaa +0 -0
  452. data/test/fixtures/sharding/xab +0 -0
  453. data/test/fixtures/sharding/xac +0 -0
  454. data/test/fixtures/sharding/xad +0 -0
  455. data/test/fixtures/sharding/xae +0 -0
  456. data/test/fixtures/sharding/xaf +0 -0
  457. data/test/fixtures/sharding/xag +0 -0
  458. data/test/fixtures/styles/box_a/runny.html.cut +0 -0
  459. data/test/fixtures/styles/box_a.html.cut +1 -0
  460. data/test/fixtures/styles/named2.html.cut +1 -0
  461. data/test/fixtures/styles/orange/apple.html.cut +1 -0
  462. data/test/fixtures/styles/template_class/named1.html.cut +1 -0
  463. data/test/fixtures/styles/template_class/results.html.cut +1 -0
  464. data/test/fixtures/styles/template_class/walky.html.cut +0 -0
  465. data/test/fixtures/styles/template_class.epub.cut +0 -0
  466. data/test/fixtures/styles/template_class.html.cut +1 -0
  467. data/test/fixtures/styles/template_class.pdf.cut +0 -0
  468. data/test/fixtures/styles/template_sub_class1.html.cut +1 -0
  469. data/test/fixtures/templates/aliases/a/a_style.html.cut +0 -0
  470. data/test/fixtures/templates/aliases/a/page.html.cut +0 -0
  471. data/test/fixtures/templates/aliases/a_alias/a_alias_style.html.cut +0 -0
  472. data/test/fixtures/templates/aliases/layouts/b.html.cut +1 -0
  473. data/test/fixtures/templates/aliases/layouts/b_alias.html.cut +1 -0
  474. data/test/fixtures/templates/aliases/layouts/c_alias.html.cut +1 -0
  475. data/test/fixtures/templates/boxes/blank_content/things.html.cut +1 -0
  476. data/test/fixtures/templates/boxes/my_box_class/christy.html.cut +1 -0
  477. data/test/fixtures/templates/boxes/thangs.html.cut +1 -0
  478. data/test/fixtures/templates/boxes/with_template_box.html.cut +1 -0
  479. data/test/fixtures/templates/content/include.html.cut +1 -0
  480. data/test/fixtures/templates/content/include_dir.html.cut +1 -0
  481. data/test/fixtures/templates/content/included.epub.cut +1 -0
  482. data/test/fixtures/templates/content/included.html.cut +1 -0
  483. data/test/fixtures/templates/content/partial/included.html.cut +1 -0
  484. data/test/fixtures/templates/content/preprocess.html.cut +1 -0
  485. data/test/fixtures/templates/content/second.html.cut +1 -0
  486. data/test/fixtures/templates/content/template.epub.cut +1 -0
  487. data/test/fixtures/templates/content/template.html.cut +1 -0
  488. data/test/fixtures/templates/default_style_class.html.cut +1 -0
  489. data/test/fixtures/templates/direct.html.cut +1 -0
  490. data/test/fixtures/templates/extended/grandparent.html.cut +10 -0
  491. data/test/fixtures/templates/extended/main.html.cut +6 -0
  492. data/test/fixtures/templates/extended/parent.html.cut +10 -0
  493. data/test/fixtures/templates/layouts/entries.html.cut +7 -0
  494. data/test/fixtures/templates/layouts/page_style.html.cut +1 -0
  495. data/test/fixtures/templates/layouts/params.html.cut +1 -0
  496. data/test/fixtures/templates/layouts/preview_render.html.cut +2 -0
  497. data/test/fixtures/templates/layouts/standard_page.html.cut +1 -0
  498. data/test/fixtures/templates/layouts/subdir_style.html.cut +1 -0
  499. data/test/fixtures/templates/layouts/template_params.html.cut +1 -0
  500. data/test/fixtures/templates/page_class/inline_style.html.cut +1 -0
  501. data/test/fixtures/templates/preview_render/inline.html.cut +0 -0
  502. data/test/fixtures/templates/publishing/layouts/dynamic.html.cut +1 -0
  503. data/test/fixtures/templates/publishing/layouts/static.html.cut +1 -0
  504. data/test/fixtures/templates/template_class/anonymous_style.html.cut +4 -0
  505. data/test/fixtures/templates/template_class/another_template.html.cut +0 -0
  506. data/test/fixtures/templates/template_class/complex_template.html.cut +6 -0
  507. data/test/fixtures/templates/template_class/complex_template.pdf.cut +6 -0
  508. data/test/fixtures/templates/template_class/default_template_style.html.cut +4 -0
  509. data/test/fixtures/templates/template_class/images_with_template.html.cut +5 -0
  510. data/test/fixtures/templates/template_class/slots_template.html.cut +5 -0
  511. data/test/fixtures/templates/template_class/slots_template.pdf.cut +5 -0
  512. data/test/fixtures/templates/template_class/this_template.epub.cut +1 -0
  513. data/test/fixtures/templates/template_class/this_template.html.cut +1 -0
  514. data/test/fixtures/templates/template_class/this_template.pdf.cut +1 -0
  515. data/test/fixtures/templates/with_default_style_class.html.cut +1 -0
  516. data/test/functional/test_application.rb +176 -0
  517. data/test/functional/test_back.rb +902 -0
  518. data/test/functional/test_front.rb +571 -0
  519. data/test/javascript/test_dom.rb +94 -0
  520. data/test/javascript/test_markdown.rb +97 -0
  521. data/test/slow/test_publishing.rb +987 -0
  522. data/test/slow/test_visibility.rb +250 -0
  523. data/test/support/custom_matchers.rb +77 -0
  524. data/test/support/timing.rb +23 -0
  525. data/test/test_helper.rb +164 -0
  526. data/test/test_javascript.rb +34 -0
  527. data/test/ui/test_page_editing.rb +167 -0
  528. data/test/ui_helper.rb +114 -0
  529. data/test/unit/test_alias.rb +254 -0
  530. data/test/unit/test_authentication.rb +510 -0
  531. data/test/unit/test_boxes.rb +497 -0
  532. data/test/unit/test_config.rb +156 -0
  533. data/test/unit/test_content.rb +221 -0
  534. data/test/unit/test_content_inheritance.rb +103 -0
  535. data/test/unit/test_extensions.rb +14 -0
  536. data/test/unit/test_fields.rb +392 -0
  537. data/test/unit/test_generators.rb +97 -0
  538. data/test/unit/test_image_size.rb +25 -0
  539. data/test/unit/test_images.rb +265 -0
  540. data/test/unit/test_layouts.rb +111 -0
  541. data/test/unit/test_logger.rb +80 -0
  542. data/test/unit/test_media.rb +70 -0
  543. data/test/unit/test_page.rb +244 -0
  544. data/test/unit/test_permissions.rb +834 -0
  545. data/test/unit/test_piece.rb +80 -0
  546. data/test/unit/test_prototype_set.rb +192 -0
  547. data/test/unit/test_prototypes.rb +102 -0
  548. data/test/unit/test_render.rb +359 -0
  549. data/test/unit/test_schema.rb +1009 -0
  550. data/test/unit/test_serialisation.rb +215 -0
  551. data/test/unit/test_site.rb +145 -0
  552. data/test/unit/test_structure.rb +85 -0
  553. data/test/unit/test_styles.rb +417 -0
  554. data/test/unit/test_templates.rb +224 -0
  555. data/test/unit/test_type_hierarchy.rb +28 -0
  556. metadata +1017 -0
@@ -0,0 +1,1009 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'test_helper'
4
+
5
+
6
+ class SchemaTest < MiniTest::Spec
7
+ include Spontaneous
8
+
9
+ UID = Spontaneous::Schema::UID
10
+
11
+ # declare these early so that Piece & Page get loaded
12
+ # and are then cleared early by the Schema.reset! call
13
+ class X < Spontaneous::Piece; end
14
+ class Y < Spontaneous::Page; end
15
+ def setup
16
+ Spontaneous::Schema.schema_loader_class = Spontaneous::Schema::PersistentMap
17
+ Spontaneous::Schema.reset!
18
+ end
19
+
20
+ context "Configurable names" do
21
+ setup do
22
+ class ::FunkyContent < Content; end
23
+ class ::MoreFunkyContent < FunkyContent; end
24
+ class ::ABCDifficultName < Content; end
25
+
26
+ class ::CustomName < ABCDifficultName
27
+ title "Some Name"
28
+ end
29
+ end
30
+
31
+ teardown do
32
+ [:FunkyContent, :MoreFunkyContent, :ABCDifficultName, :CustomName].each do |klass|
33
+ Object.send(:remove_const, klass)
34
+ end
35
+ end
36
+
37
+ should "default to generated version" do
38
+ FunkyContent.default_title.should == "Funky Content"
39
+ FunkyContent.title.should == "Funky Content"
40
+ MoreFunkyContent.title.should == "More Funky Content"
41
+ ABCDifficultName.default_title.should == "ABC Difficult Name"
42
+ ABCDifficultName.title.should == "ABC Difficult Name"
43
+ end
44
+
45
+ should "be settable" do
46
+ CustomName.title.should == "Some Name"
47
+ FunkyContent.title "Content Class"
48
+ FunkyContent.title.should == "Content Class"
49
+ end
50
+
51
+ should "be settable using =" do
52
+ FunkyContent.title = "Content Class"
53
+ FunkyContent.title.should == "Content Class"
54
+ end
55
+
56
+ should "not inherit from superclass" do
57
+ FunkyContent.title = "Custom Name"
58
+ MoreFunkyContent.title.should == "More Funky Content"
59
+ end
60
+ end
61
+
62
+ context "Persistent maps" do
63
+ context "Schema UIDs" do
64
+ setup do
65
+ Spontaneous.schema_map = File.expand_path('../../fixtures/schema/schema.yml', __FILE__)
66
+ class SchemaClass < Page
67
+ field :description
68
+ style :simple
69
+ layout :clean
70
+ box :posts
71
+ end
72
+ @instance = SchemaClass.new
73
+ end
74
+
75
+ teardown do
76
+ SchemaTest.send(:remove_const, :SchemaClass) rescue nil
77
+ end
78
+
79
+ # should "be 12 characters long" do
80
+ # Schema::UID.generate.to_s.length.should == 12
81
+ # end
82
+
83
+ should "be unique" do
84
+ ids = (0..10000).map { Schema::UID.generate }
85
+ ids.uniq.length.should == ids.length
86
+ end
87
+
88
+ should "be singletons" do
89
+ a = UID["xxxxxxxxxxxx"]
90
+ b = UID["xxxxxxxxxxxx"]
91
+ c = UID["ffffffffffff"]
92
+ a.object_id.should == b.object_id
93
+ a.should == b
94
+ c.object_id.should_not == b.object_id
95
+ c.should_not == b
96
+ end
97
+
98
+ should "not be creatable" do
99
+ lambda { UID.new('sadf') }.must_raise(NoMethodError)
100
+ end
101
+
102
+ should "return nil if passed nil" do
103
+ UID[nil].should be_nil
104
+ end
105
+
106
+ should "return nil if passed an empty string" do
107
+ UID[""].should be_nil
108
+ end
109
+
110
+ should "return the same UID if passed one" do
111
+ a = UID["xxxxxxxxxxxx"]
112
+ UID[a].should == a
113
+ end
114
+
115
+ should "test as equal to its string representation" do
116
+ UID["llllllllllll"].should == "llllllllllll"
117
+ end
118
+
119
+ should "be readable by content classes" do
120
+ SchemaClass.schema_id.should == UID["xxxxxxxxxxxx"]
121
+ end
122
+
123
+ should "be readable by fields" do
124
+ @instance.fields[:description].schema_id.should == UID["ffffffffffff"]
125
+ end
126
+
127
+ should "be readable by boxes" do
128
+ @instance.boxes[:posts].schema_id.should == UID["bbbbbbbbbbbb"]
129
+ end
130
+
131
+ should "be readable by styles" do
132
+ @instance.styles[:simple].schema_id.should == UID["ssssssssssss"]
133
+ end
134
+
135
+ should "be readable by layouts" do
136
+ @instance.layout.name.should == :clean
137
+ @instance.layout.schema_id.should == UID["llllllllllll"]
138
+ end
139
+
140
+ context "lookups" do
141
+ should "return classes" do
142
+ Schema["xxxxxxxxxxxx"].should == SchemaClass
143
+ end
144
+ should "return fields" do
145
+ Schema["ffffffffffff"].should == SchemaClass.field_prototypes[:description]
146
+ end
147
+ should "return boxes" do
148
+ Schema["bbbbbbbbbbbb"].should == SchemaClass.box_prototypes[:posts]
149
+ end
150
+ should "return styles" do
151
+ Schema["ssssssssssss"].should == SchemaClass.style_prototypes[:simple]
152
+ end
153
+ should "return layouts" do
154
+ Schema["llllllllllll"].should == SchemaClass.layout_prototypes[:clean]
155
+ end
156
+ end
157
+ end
158
+
159
+ context "schema verification" do
160
+ setup do
161
+ Spontaneous.schema_map = File.expand_path('../../fixtures/schema/before.yml', __FILE__)
162
+ class ::Page < Spontaneous::Page
163
+ field :title
164
+ end
165
+ class B < ::Page; end
166
+ class C < Content; end
167
+ class D < Content; end
168
+ class O < Box; end
169
+ B.field :description
170
+ B.field :author
171
+ B.box :promotions do
172
+ field :field1
173
+ field :field2
174
+ style :style1
175
+ style :style2
176
+ end
177
+ B.box :publishers, :type => O
178
+ B.style :inline
179
+ B.style :outline
180
+ B.layout :thin
181
+ B.layout :fat
182
+
183
+ O.field :ofield1
184
+ O.field :ofield2
185
+ O.style :ostyle1
186
+ O.style :ostyle2
187
+
188
+ # have to use mocking because schema class list is totally fecked up
189
+ # after running other tests
190
+ # TODO: look into reliable, non-harmful way of clearing out the schema state
191
+ # between tests
192
+ # Schema.stubs(:classes).returns([B, C, D, O])
193
+ # Schema.classes.should == [B, C, D, O]
194
+ ::Page.schema_id.should == UID["tttttttttttt"]
195
+ B.schema_id.should == UID["bbbbbbbbbbbb"]
196
+ C.schema_id.should == UID["cccccccccccc"]
197
+ D.schema_id.should == UID["dddddddddddd"]
198
+ O.schema_id.should == UID["oooooooooooo"]
199
+ end
200
+
201
+ teardown do
202
+ Object.send(:remove_const, :Page) rescue nil
203
+ SchemaTest.send(:remove_const, :B) rescue nil
204
+ SchemaTest.send(:remove_const, :C) rescue nil
205
+ SchemaTest.send(:remove_const, :D) rescue nil
206
+ SchemaTest.send(:remove_const, :E) rescue nil
207
+ SchemaTest.send(:remove_const, :F) rescue nil
208
+ SchemaTest.send(:remove_const, :O) rescue nil
209
+ end
210
+
211
+ should "return the right schema anme for inherited box fields" do
212
+ f = B.boxes[:publishers].instance_class.field :newfield
213
+ B.boxes[:publishers].instance_class.fields.first.schema_name.should == "field/oooooooooooo/ofield1"
214
+ f.schema_name.should == "field/publishers00/newfield"
215
+ end
216
+
217
+ should "detect addition of classes" do
218
+ class E < Content; end
219
+ Schema.stubs(:classes).returns([B, C, D, E])
220
+ exception = nil
221
+ begin
222
+ Schema.validate_schema
223
+ flunk("Validation should raise an exception")
224
+ rescue Spontaneous::SchemaModificationError => e
225
+ exception = e
226
+ end
227
+ exception.added_classes.should == [E]
228
+ # need to explicitly define solution to validation error
229
+ # Schema.expects(:generate).returns('dddddddddddd')
230
+ # D.schema_id.should == 'dddddddddddd'
231
+ end
232
+
233
+ should "detect removal of classes" do
234
+ SchemaTest.send(:remove_const, :C) rescue nil
235
+ SchemaTest.send(:remove_const, :D) rescue nil
236
+ Schema.stubs(:classes).returns([::Page, B, O])
237
+ begin
238
+ Schema.validate_schema
239
+ flunk("Validation should raise an exception")
240
+ rescue Spontaneous::SchemaModificationError => e
241
+ exception = e
242
+ end
243
+ exception.removed_classes.map { |c| c.name }.sort.should == ["SchemaTest::C", "SchemaTest::D"]
244
+ end
245
+
246
+ should "detect multiple removals & additions of classes" do
247
+ SchemaTest.send(:remove_const, :C) rescue nil
248
+ SchemaTest.send(:remove_const, :D) rescue nil
249
+ class E < Content; end
250
+ class F < Content; end
251
+ Schema.stubs(:classes).returns([::Page, B, E, F, O])
252
+ begin
253
+ Schema.validate_schema
254
+ flunk("Validation should raise an exception if schema is modified")
255
+ rescue Spontaneous::SchemaModificationError => e
256
+ exception = e
257
+ end
258
+ exception.added_classes.should == [E, F]
259
+ exception.removed_classes.map {|c| c.name}.sort.should == ["SchemaTest::C", "SchemaTest::D"]
260
+ end
261
+
262
+ should "detect addition of fields" do
263
+ B.field :name
264
+ C.field :location
265
+ C.field :description
266
+ begin
267
+ Schema.validate_schema
268
+ flunk("Validation should raise an exception if new fields are added")
269
+ rescue Spontaneous::SchemaModificationError => e
270
+ exception = e
271
+ end
272
+ exception.added_fields.should == [B.field_prototypes[:name], C.field_prototypes[:location], C.field_prototypes[:description]]
273
+ end
274
+
275
+ should "detect removal of fields" do
276
+ field = B.field_prototypes[:author]
277
+ B.stubs(:field_prototypes).returns({:author => field})
278
+ B.stubs(:fields).returns([field])
279
+ begin
280
+ Schema.validate_schema
281
+ flunk("Validation should raise an exception if fields are removed")
282
+ rescue Spontaneous::SchemaModificationError => e
283
+ exception = e
284
+ end
285
+ exception.removed_fields.length == 1
286
+ exception.removed_fields[0].name.should == "description"
287
+ exception.removed_fields[0].owner.should == SchemaTest::B
288
+ exception.removed_fields[0].category.should == :field
289
+ end
290
+
291
+ should "detect addition of boxes" do
292
+ B.box :changes
293
+ B.box :updates
294
+ begin
295
+ Schema.validate_schema
296
+ flunk("Validation should raise an exception if new boxes are added")
297
+ rescue Spontaneous::SchemaModificationError => e
298
+ exception = e
299
+ end
300
+ exception.added_boxes.should == [B.boxes[:changes], B.boxes[:updates]]
301
+ end
302
+
303
+ should "detect removal of boxes" do
304
+ boxes = S::Collections::PrototypeSet.new
305
+ boxes[:promotions] = B.boxes[:promotions]
306
+
307
+ B.stubs(:box_prototypes).returns(boxes)
308
+ begin
309
+ Schema.validate_schema
310
+ flunk("Validation should raise an exception if fields are removed")
311
+ rescue Spontaneous::SchemaModificationError => e
312
+ exception = e
313
+ end
314
+ exception.removed_boxes.length.should == 1
315
+ exception.removed_boxes[0].name.should == "publishers"
316
+ exception.removed_boxes[0].owner.should == SchemaTest::B
317
+ exception.removed_boxes[0].category.should == :box
318
+ end
319
+
320
+ should "detect addition of styles" do
321
+ B.style :fancy
322
+ B.style :dirty
323
+ begin
324
+ Schema.validate_schema
325
+ flunk("Validation should raise an exception if new styles are added")
326
+ rescue Spontaneous::SchemaModificationError => e
327
+ exception = e
328
+ end
329
+ exception.added_styles.should == [B.styles.detect{ |s| s.name == :fancy }, B.styles.detect{ |s| s.name == :dirty }]
330
+ end
331
+
332
+ should "detect removal of styles" do
333
+ style = B.styles[:inline]
334
+ B.styles.expects(:order).returns([:inline])
335
+ B.styles.stubs(:[]).with(:inline).returns(style)
336
+ B.styles.stubs(:[]).with(:outline).returns(nil)
337
+ begin
338
+ Schema.validate_schema
339
+ flunk("Validation should raise an exception if styles are removed")
340
+ rescue Spontaneous::SchemaModificationError => e
341
+ exception = e
342
+ end
343
+ exception.removed_styles.length.should == 1
344
+ exception.removed_styles[0].name.should == "outline"
345
+ exception.removed_styles[0].owner.should == SchemaTest::B
346
+ exception.removed_styles[0].category.should == :style
347
+ end
348
+
349
+ should "detect addition of layouts" do
350
+ B.layout :fancy
351
+ B.layout :dirty
352
+ begin
353
+ Schema.validate_schema
354
+ flunk("Validation should raise an exception if new layouts are added")
355
+ rescue Spontaneous::SchemaModificationError => e
356
+ exception = e
357
+ end
358
+ exception.added_layouts.should == [B.layouts.detect{ |s| s.name == :fancy }, B.layouts.detect{ |s| s.name == :dirty }]
359
+ end
360
+
361
+ should "detect removal of layouts" do
362
+ layout = B.layouts[:thin]
363
+ B.layouts.expects(:order).returns([:thin])
364
+ B.layouts.stubs(:[]).with(:thin).returns(layout)
365
+ B.layouts.stubs(:[]).with(:fat).returns(nil)
366
+ begin
367
+ Schema.validate_schema
368
+ flunk("Validation should raise an exception if fields are removed")
369
+ rescue Spontaneous::SchemaModificationError => e
370
+ exception = e
371
+ end
372
+ exception.removed_layouts.length.should == 1
373
+ exception.removed_layouts[0].name.should == "fat"
374
+ exception.removed_layouts[0].owner.should == SchemaTest::B
375
+ exception.removed_layouts[0].category.should == :layout
376
+ end
377
+
378
+ should "detect addition of fields to anonymous boxes" do
379
+ f1 = B.boxes[:publishers].instance_class.field :field3
380
+ f2 = B.boxes[:promotions].instance_class.field :field3
381
+ begin
382
+ Schema.validate_schema
383
+ flunk("Validation should raise an exception if new fields are added to anonymous boxes")
384
+ rescue Spontaneous::SchemaModificationError => e
385
+ exception = e
386
+ end
387
+ assert_same_elements exception.added_fields, [f2, f1]
388
+ end
389
+
390
+ should "detect removal of fields from anonymous boxes" do
391
+ f2 = B.boxes[:promotions].instance_class.field_prototypes[:field2]
392
+ B.boxes[:promotions].instance_class.stubs(:field_prototypes).returns({:field2 => f2})
393
+ B.boxes[:promotions].instance_class.stubs(:fields).returns([f2])
394
+ begin
395
+ Schema.validate_schema
396
+ flunk("Validation should raise an exception if fields are removed from anonymous boxes")
397
+ rescue Spontaneous::SchemaModificationError => e
398
+ exception = e
399
+ end
400
+ exception.removed_fields.length.should == 1
401
+ exception.removed_fields[0].name.should == "field1"
402
+ exception.removed_fields[0].owner.instance_class.should == SchemaTest::B.boxes[:promotions].instance_class
403
+ exception.removed_fields[0].category.should == :field
404
+ end
405
+
406
+ should "detect addition of fields to box types" do
407
+ O.field :name
408
+ begin
409
+ Schema.validate_schema
410
+ flunk("Validation should raise an exception if new fields are added to boxes")
411
+ rescue Spontaneous::SchemaModificationError => e
412
+ exception = e
413
+ end
414
+ exception.added_fields.should == [O.field_prototypes[:name]]
415
+ end
416
+
417
+ # should "detect removal of fields from box types" do
418
+ # skip "stubbing is messing up the field hierarchy in weird ways"
419
+ # fields = [O.field_prototypes[:ofield1]]
420
+ # O.stubs(:fields).returns(fields)
421
+ # begin
422
+ # Schema.validate_schema
423
+ # flunk("Validation should raise an exception if fields are removed")
424
+ # rescue Spontaneous::SchemaModificationError => e
425
+ # exception = e
426
+ # end
427
+ # exception.removed_fields.length == 1
428
+ # exception.removed_fields[0].name.should == "ofield2"
429
+ # exception.removed_fields[0].owner.should == SchemaTest::O
430
+ # exception.removed_fields[0].category.should == :field
431
+ # end
432
+
433
+ should "detect addition of styles to box types"
434
+ should "detect removal of styles from box types"
435
+
436
+ should "detect addition of styles to anonymous boxes" do
437
+ s1 = B.boxes[:publishers].instance_class.style :style3
438
+ s2 = B.boxes[:promotions].instance_class.style :style3
439
+ begin
440
+ Schema.validate_schema
441
+ flunk("Validation should raise an exception if new fields are added to anonymous boxes")
442
+ rescue Spontaneous::SchemaModificationError => e
443
+ exception = e
444
+ end
445
+ assert_same_elements exception.added_styles, [s2, s1]
446
+ end
447
+
448
+ should "detect removal of styles from anonymous boxes" do
449
+ klass = B.boxes[:promotions].instance_class
450
+ style = klass.styles.first
451
+ klass.styles.expects(:order).returns([style.name])
452
+ klass.styles.stubs(:[]).with(style.name).returns(style)
453
+ klass.styles.stubs(:[]).with(:style2).returns(nil)
454
+ begin
455
+ Schema.validate_schema
456
+ flunk("Validation should raise an exception if styles are removed")
457
+ rescue Spontaneous::SchemaModificationError => e
458
+ exception = e
459
+ end
460
+ exception.removed_styles.length.should == 1
461
+ exception.removed_styles[0].name.should == "style2"
462
+ exception.removed_styles[0].owner.instance_class.should == SchemaTest::B.boxes[:promotions].instance_class
463
+ exception.removed_styles[0].category.should == :style
464
+ end
465
+ end
466
+ end
467
+ context "Transient (testing) maps" do
468
+ setup do
469
+ Spontaneous::Schema.schema_loader_class = Spontaneous::Schema::TransientMap
470
+ Spontaneous::Schema.reset!
471
+ class V < Spontaneous::Piece; end
472
+ class W < Spontaneous::Piece; end
473
+ end
474
+ teardown do
475
+ self.class.send(:remove_const, :V)
476
+ self.class.send(:remove_const, :W)
477
+ end
478
+
479
+ should "create uids on demand" do
480
+ V.schema_id.should_not be_nil
481
+ W.schema_id.should_not be_nil
482
+ V.schema_id.should_not == W.schema_id
483
+ end
484
+
485
+ should "return consistent ids within a session" do
486
+ a = V.schema_id
487
+ b = V.schema_id
488
+ a.should equal?(b)
489
+ end
490
+
491
+ should "return UID objects" do
492
+ V.schema_id.must_be_instance_of(Spontaneous::Schema::UID)
493
+ end
494
+ end
495
+
496
+ context "Map writing" do
497
+ context "Non-existant maps" do
498
+ setup do
499
+ S::Schema.reset!
500
+ @map_file = File.expand_path('../../../tmp/schema.yml', __FILE__)
501
+ ::File.exists?(@map_file).should be_false
502
+ Spontaneous.schema_map = @map_file
503
+ class ::A < Spontaneous::Page
504
+ field :title
505
+ field :introduction
506
+ layout :sparse
507
+ box :posts do
508
+ field :description
509
+ end
510
+ end
511
+ class ::B < Spontaneous::Piece
512
+ field :location
513
+ style :daring
514
+ end
515
+ end
516
+ teardown do
517
+ Object.send(:remove_const, :A) rescue nil
518
+ Object.send(:remove_const, :B) rescue nil
519
+ FileUtils.rm(@map_file) if ::File.exists?(@map_file)
520
+ end
521
+ should "get created with verification" do
522
+ S::Schema.validate!
523
+ classes = [ ::A, ::B]
524
+ # would like to do all of this using mocks, but don't know how to do that
525
+ # without fecking up the whole schema id creation process
526
+ expected = Hash[ classes.map { |klass| [ klass.schema_id.to_s, klass.schema_name ] } ]
527
+ expected.merge!({
528
+ A.field_prototypes[:title].schema_id.to_s => A.field_prototypes[:title].schema_name,
529
+ A.field_prototypes[:introduction].schema_id.to_s => A.field_prototypes[:introduction].schema_name,
530
+ A.layout_prototypes[:sparse].schema_id.to_s => A.layout_prototypes[:sparse].schema_name,
531
+ A.boxes[:posts].schema_id.to_s => A.boxes[:posts].schema_name,
532
+ A.boxes[:posts].field_prototypes[:description].schema_id.to_s => A.boxes[:posts].field_prototypes[:description].schema_name,
533
+ B.field_prototypes[:location].schema_id.to_s => B.field_prototypes[:location].schema_name,
534
+ B.style_prototypes[:daring].schema_id.to_s => B.style_prototypes[:daring].schema_name,
535
+ })
536
+ File.exists?(@map_file).should be_true
537
+ YAML.load_file(@map_file).should == expected
538
+ end
539
+ end
540
+ context "change resolution" do
541
+ setup do
542
+ S::Schema.reset!
543
+ @map_file = File.expand_path('../../../tmp/schema.yml', __FILE__)
544
+ FileUtils.mkdir_p(File.dirname(@map_file))
545
+ FileUtils.cp(File.expand_path('../../fixtures/schema/resolvable.yml', __FILE__), @map_file)
546
+ Spontaneous.schema_map = @map_file
547
+ class ::A < Spontaneous::Page
548
+ field :title
549
+ field :introduction
550
+ layout :sparse
551
+ box :posts do
552
+ field :description
553
+ end
554
+ end
555
+ class ::B < Spontaneous::Piece
556
+ field :location
557
+ field :duration
558
+ style :daring
559
+ end
560
+ S::Schema.validate!
561
+ A.schema_id.should == S::Schema::UID["qLcxinA008"]
562
+ end
563
+
564
+ teardown do
565
+ Object.send(:remove_const, :A) rescue nil
566
+ Object.send(:remove_const, :B) rescue nil
567
+ Object.send(:remove_const, :X) rescue nil
568
+ Object.send(:remove_const, :Y) rescue nil
569
+ S::Content.delete
570
+ FileUtils.rm(@map_file) if ::File.exists?(@map_file)
571
+ end
572
+
573
+ should "be done automatically if only additions are found" do
574
+ A.field :moose
575
+ class ::X < ::A
576
+ field :wild
577
+ box :monkeys do
578
+ field :banana
579
+ end
580
+ layout :rich
581
+ end
582
+ class ::Y < ::B
583
+ style :risky
584
+ end
585
+ S::Schema.validate!
586
+ ::X.schema_id.should_not be_nil
587
+ ::Y.schema_id.should_not be_nil
588
+ ::A.field_prototypes[:moose].schema_id.should_not be_nil
589
+
590
+ m = YAML.load_file(@map_file)
591
+ m[::A.field_prototypes[:moose].schema_id.to_s].should == ::A.field_prototypes[:moose].schema_name
592
+ m[::X.schema_id.to_s].should == ::X.schema_name
593
+ m[::Y.schema_id.to_s].should == ::Y.schema_name
594
+ m[::X.field_prototypes[:wild].schema_id.to_s].should == ::X.field_prototypes[:wild].schema_name
595
+ m[::X.boxes[:monkeys].schema_id.to_s].should == ::X.boxes[:monkeys].schema_name
596
+ m[::X.boxes[:monkeys].field_prototypes[:banana].schema_id.to_s].should == ::X.boxes[:monkeys].field_prototypes[:banana].schema_name
597
+ m[::X.layout_prototypes[:rich].schema_id.to_s].should == ::X.layout_prototypes[:rich].schema_name
598
+ end
599
+
600
+
601
+ should "be done automatically if only classes have been removed" do
602
+ uid = B.schema_id.to_s
603
+ Object.send(:remove_const, :B)
604
+ S::Schema.stubs(:classes).returns([::A])
605
+ S::Schema.reload!
606
+ S::Schema.validate!
607
+ m = YAML.load_file(@map_file)
608
+ m.key?(uid).should be_false
609
+ end
610
+
611
+ should "be done automatically if only boxes have been removed" do
612
+ uid = A.boxes[:posts].schema_id.to_s
613
+ A.stubs(:box_prototypes).returns(S::Collections::PrototypeSet.new)
614
+ S::Schema.stubs(:classes).returns([A, B])
615
+ S::Schema.reload!
616
+ S::Schema.validate!
617
+ m = YAML.load_file(@map_file)
618
+ m.key?(uid).should be_false
619
+ end
620
+
621
+ should "be done automatically if only fields have been removed" do
622
+ f1 = A.field_prototypes[:title]
623
+ uid = f1.schema_id.to_s
624
+ f2 = A.field_prototypes[:introduction]
625
+ A.stubs(:field_prototypes).returns({:introduction => f2})
626
+ A.stubs(:fields).returns([f2])
627
+ S::Schema.reload!
628
+ S::Schema.validate!
629
+ m = YAML.load_file(@map_file)
630
+ m.key?(uid).should be_false
631
+ end
632
+
633
+ should "be done automatically in presence of independent addition inside type and of type" do
634
+ A.field :moose
635
+ uid = B.schema_id.to_s
636
+ Object.send(:remove_const, :B)
637
+ S::Schema.stubs(:classes).returns([::A])
638
+ S::Schema.reload!
639
+ S::Schema.validate!
640
+ ::A.field_prototypes[:moose].schema_id.should_not be_nil
641
+
642
+ m = YAML.load_file(@map_file)
643
+ m[::A.field_prototypes[:moose].schema_id.to_s].should == ::A.field_prototypes[:moose].schema_name
644
+ m.key?(uid).should be_false
645
+ end
646
+
647
+ should "be done automatically in presence of independent addition & removal of fields" do
648
+ A.field :moose
649
+ f1 = B.field_prototypes[:location]
650
+ uid = f1.schema_id.to_s
651
+ f2 = B.field_prototypes[:duration]
652
+ B.stubs(:field_prototypes).returns({:duration => f2})
653
+ B.stubs(:fields).returns([f2])
654
+ S::Schema.reload!
655
+ S::Schema.validate!
656
+
657
+ ::A.field_prototypes[:moose].schema_id.should_not be_nil
658
+
659
+ m = YAML.load_file(@map_file)
660
+ m[::A.field_prototypes[:moose].schema_id.to_s].should == ::A.field_prototypes[:moose].schema_name
661
+ m.key?(uid).should be_false
662
+ end
663
+
664
+ should "be done automatically in presence of independent changes to boxes & fields" do
665
+ B.field :crisis
666
+ uid = A.boxes[:posts].schema_id.to_s
667
+ A.stubs(:box_prototypes).returns(S::Collections::PrototypeSet.new)
668
+ S::Schema.stubs(:classes).returns([A, B])
669
+ S::Schema.reload!
670
+ S::Schema.validate!
671
+
672
+ ::B.field_prototypes[:crisis].schema_id.should_not be_nil
673
+ m = YAML.load_file(@map_file)
674
+ m.key?(uid).should be_false
675
+ end
676
+
677
+ should "be done automatically in presence of independent changes to classes, boxes & fields" do
678
+ class ::X < B; end
679
+ uid = A.boxes[:posts].schema_id.to_s
680
+ A.stubs(:box_prototypes).returns(S::Collections::PrototypeSet.new)
681
+ B.field :crisis
682
+ B.box :circus
683
+ A.field :crisis
684
+ S::Schema.stubs(:classes).returns([::A, ::B, ::X])
685
+ S::Schema.reload!
686
+ S::Schema.validate!
687
+
688
+ ::A.field_prototypes[:crisis].schema_id.should_not be_nil
689
+ m = YAML.load_file(@map_file)
690
+
691
+ box = ::B.boxes[:circus]
692
+ m[box.schema_id.to_s].should == box.schema_name
693
+
694
+ field = ::A.field_prototypes[:crisis]
695
+ m[field.schema_id.to_s].should == field.schema_name
696
+
697
+ field = ::B.field_prototypes[:crisis]
698
+ m[field.schema_id.to_s].should == field.schema_name
699
+
700
+ m.key?(uid).should be_false
701
+ end
702
+
703
+
704
+ # sanity check
705
+ should "still raise error in case of addition & deletion" do
706
+ A.field :added
707
+ f1 = A.field_prototypes[:title]
708
+ f2 = A.field_prototypes[:added]
709
+ uid = f1.schema_id.to_s
710
+ f3 = A.field_prototypes[:introduction]
711
+ A.stubs(:field_prototypes).returns({:added => f2, :introduction => f3})
712
+ A.stubs(:fields).returns([f2, f3])
713
+ S::Schema.reload!
714
+ lambda { S::Schema.validate! }.must_raise(Spontaneous::SchemaModificationError)
715
+ end
716
+
717
+ should "still raise error in case of addition & deletion of classes" do
718
+ class ::X < A; end
719
+ uid = B.schema_id.to_s
720
+ Object.send(:remove_const, :B)
721
+ S::Schema.stubs(:classes).returns([::A, ::X])
722
+ S::Schema.reload!
723
+ lambda { S::Schema.validate! }.must_raise(Spontaneous::SchemaModificationError)
724
+ end
725
+
726
+ should "delete box content when a box is removed" do
727
+ instance = A.new
728
+ piece1 = B.new
729
+ piece2 = B.new
730
+ instance.posts << piece1
731
+ instance.posts << piece2
732
+ instance.save
733
+ instance = S::Content[instance.id]
734
+ instance.posts.pieces.length.should == 2
735
+ Content.count.should == 3
736
+ uid = A.boxes[:posts].schema_id.to_s
737
+ A.stubs(:box_prototypes).returns(S::Collections::PrototypeSet.new)
738
+ S::Schema.stubs(:classes).returns([A, B])
739
+ S::Schema.reload!
740
+ S::Schema.validate!
741
+ Content.count.should == 1
742
+ S::Content[instance.id].should == instance
743
+ end
744
+
745
+ context "which isn't automatically resolvable" do
746
+ context "with one field removed" do
747
+ setup do
748
+ A.field :a
749
+ A.field :b
750
+ @df1 = A.field_prototypes[:title]
751
+ @af1 = A.field_prototypes[:a]
752
+ @af2 = A.field_prototypes[:b]
753
+ @uid = @df1.schema_id.to_s
754
+ @f3 = A.field_prototypes[:introduction]
755
+ A.stubs(:field_prototypes).returns({:a => @af1, :b => @af2, :introduction => @f3})
756
+ A.stubs(:fields).returns([@af1, @af2, @f3])
757
+ S::Schema.reload!
758
+ begin
759
+ S::Schema.validate!
760
+ flunk("Validation should raise error when adding & deleting fields")
761
+ rescue Spontaneous::SchemaModificationError => e
762
+ @modification = e.modification
763
+ end
764
+ end
765
+ should "return list of solutions for removal of one field" do
766
+ # add :a, :b, delete :title
767
+ # add :b, rename :title => :a
768
+ # add :a, rename :title => :b
769
+ @modification.actions.description.should =~ /field 'title'/
770
+ @modification.actions.length.should == 3
771
+ action = @modification.actions[0]
772
+ action.action.should == :delete
773
+ action.source.should == @df1.schema_id
774
+ action.description.should =~ /delete field 'title'/i
775
+ action = @modification.actions[1]
776
+ action.action.should == :rename
777
+ action.source.should == @df1.schema_id
778
+ action.description.should =~ /rename field 'title' to 'a'/i
779
+ action = @modification.actions[2]
780
+ action.action.should == :rename
781
+ action.source.should == @df1.schema_id
782
+ action.description.should =~ /rename field 'title' to 'b'/i
783
+ end
784
+
785
+ should "enable fixing the problem by deleting field from schema" do
786
+ action = @modification.actions[0]
787
+ begin
788
+ S::Schema.apply(action)
789
+ rescue Spontaneous::SchemaModificationError => e
790
+ flunk("Deletion of field should have resolved schema error")
791
+ end
792
+
793
+ m = YAML.load_file(@map_file)
794
+ m.key?(@uid).should be_false
795
+ end
796
+
797
+ should "enable fixing the problem by renaming field 'a'" do
798
+ action = @modification.actions[1]
799
+ begin
800
+ S::Schema.apply(action)
801
+ rescue Spontaneous::SchemaModificationError => e
802
+ flunk("Renaming of field should have resolved schema error")
803
+ end
804
+ m = YAML.load_file(@map_file)
805
+ m[@uid].should == @af1.schema_name
806
+ end
807
+
808
+ should "enable fixing the problem by renaming field 'b'" do
809
+ action = @modification.actions[2]
810
+ begin
811
+ S::Schema.apply(action)
812
+ rescue Spontaneous::SchemaModificationError => e
813
+ flunk("Renaming of field should have resolved schema error")
814
+ end
815
+ m = YAML.load_file(@map_file)
816
+ m[@uid].should == @af2.schema_name
817
+ end
818
+ end
819
+
820
+ context "with two fields removed" do
821
+ setup do
822
+ A.field :a
823
+ A.field :b
824
+ A.field :c
825
+ @df1 = A.field_prototypes[:title]
826
+ @df2 = A.field_prototypes[:introduction]
827
+ @af1 = A.field_prototypes[:a]
828
+ @af2 = A.field_prototypes[:b]
829
+ @af3 = A.field_prototypes[:c]
830
+ @uid1 = @df1.schema_id.to_s
831
+ @uid2 = @df2.schema_id.to_s
832
+ A.stubs(:field_prototypes).returns({:a => @af1, :b => @af2, :c => @af3})
833
+ A.stubs(:fields).returns([@af1, @af2, @af3])
834
+ S::Schema.reload!
835
+ begin
836
+ S::Schema.validate!
837
+ flunk("Validation should raise error when adding & deleting fields")
838
+ rescue Spontaneous::SchemaModificationError => e
839
+ @modification = e.modification
840
+ end
841
+ end
842
+ should "return list of solutions" do
843
+ # add :a, :b; delete :title, :introduction
844
+ # rename :title => :a, :introduction => :b
845
+ # rename :introduction => :a, :title => :b
846
+ # add :a; delete :introduction; rename :title => :b
847
+ # add :a; delete :title; rename :introduction => :b
848
+ # add :b; delete :introduction; rename :title => :a
849
+ # add :b; delete :title; rename :introduction => :a
850
+ @modification.actions.description.should =~ /field 'title'/
851
+ @modification.actions.length.should == 4
852
+ action = @modification.actions[0]
853
+ action.action.should == :delete
854
+ action.source.should == @df1.schema_id
855
+ action.description.should =~ /delete field 'title'/i
856
+ action = @modification.actions[1]
857
+ action.action.should == :rename
858
+ action.source.should == @df1.schema_id
859
+ action.description.should =~ /rename field 'title' to 'a'/i
860
+ action = @modification.actions[2]
861
+ action.action.should == :rename
862
+ action.source.should == @df1.schema_id
863
+ action.description.should =~ /rename field 'title' to 'b'/i
864
+ action = @modification.actions[3]
865
+ action.action.should == :rename
866
+ action.source.should == @df1.schema_id
867
+ action.description.should =~ /rename field 'title' to 'c'/i
868
+ end
869
+
870
+ should "enable fixing the problem by deleting both fields" do
871
+ action = @modification.actions[0]
872
+ begin
873
+ S::Schema.apply(action)
874
+ flunk("Deletion of field should not have resolved schema error")
875
+ rescue Spontaneous::SchemaModificationError => e
876
+ modification = e.modification
877
+ end
878
+ action = modification.actions[0]
879
+
880
+ begin
881
+ S::Schema.apply(action)
882
+ rescue Spontaneous::SchemaModificationError => e
883
+ flunk("Deletion of field should have resolved schema error")
884
+ end
885
+ m = YAML.load_file(@map_file)
886
+ m.key?(@uid1).should be_false
887
+ m.key?(@uid2).should be_false
888
+ end
889
+
890
+ should "enable fixing the problem by deleting one field and renaming other as 'a'" do
891
+ action = @modification.actions[0]
892
+ begin
893
+ S::Schema.apply(action)
894
+ flunk("Deletion of field should not have resolved schema error")
895
+ rescue Spontaneous::SchemaModificationError => e
896
+ modification = e.modification
897
+ end
898
+ action = modification.actions[1]
899
+
900
+ begin
901
+ S::Schema.apply(action)
902
+ rescue Spontaneous::SchemaModificationError => e
903
+ flunk("Deletion of field should have resolved schema error")
904
+ end
905
+ m = YAML.load_file(@map_file)
906
+ m.key?(@uid1).should be_false
907
+ m.key?(@uid2).should be_true
908
+ m[@uid2].should == @af1.schema_name
909
+ end
910
+
911
+ should "enable fixing the problem by renaming one field as 'c' and deleting other" do
912
+ action = @modification.actions[3]
913
+ begin
914
+ S::Schema.apply(action)
915
+ flunk("Renaming of field should not have resolved schema error")
916
+ rescue Spontaneous::SchemaModificationError => e
917
+ modification = e.modification
918
+ end
919
+ action = modification.actions[0]
920
+
921
+ begin
922
+ S::Schema.apply(action)
923
+ rescue Spontaneous::SchemaModificationError => e
924
+ flunk("Deletion of field should have resolved schema error")
925
+ end
926
+ m = YAML.load_file(@map_file)
927
+ m.key?(@uid1).should be_true
928
+ m.key?(@uid2).should be_false
929
+ m[@uid1].should == @af3.schema_name
930
+ end
931
+
932
+ should "enable fixing the problem by renaming one field as 'c' and renaming other as 'b'" do
933
+ action = @modification.actions[3]
934
+ begin
935
+ S::Schema.apply(action)
936
+ flunk("Renaming of field should not have resolved schema error")
937
+ rescue Spontaneous::SchemaModificationError => e
938
+ modification = e.modification
939
+ end
940
+ action = modification.actions[2]
941
+
942
+ begin
943
+ S::Schema.apply(action)
944
+ rescue Spontaneous::SchemaModificationError => e
945
+ flunk("Deletion of field should have resolved schema error")
946
+ end
947
+ m = YAML.load_file(@map_file)
948
+ m.key?(@uid1).should be_true
949
+ m.key?(@uid2).should be_true
950
+ m[@uid1].should == @af3.schema_name
951
+ m[@uid2].should == @af2.schema_name
952
+ end
953
+
954
+ context "and two boxes removed" do
955
+ setup do
956
+ @db1 = A.boxes[:posts]
957
+ A.box :added1
958
+ A.box :added2
959
+ @ab1 = A.boxes[:added1]
960
+ @ab2 = A.boxes[:added2]
961
+ boxes = S::Collections::PrototypeSet.new
962
+ boxes[:added1] = @ab1
963
+ boxes[:added2] = @ab2
964
+ A.stubs(:box_prototypes).returns(boxes)
965
+ classes = S::Schema.classes.dup
966
+ classes.delete(A::PostsBox)
967
+ S::Schema.stubs(:classes).returns(classes)
968
+ S::Schema.reload!
969
+ begin
970
+ S::Schema.validate!
971
+ flunk("Validation should raise error when adding & deleting fields")
972
+ rescue Spontaneous::SchemaModificationError => e
973
+ @modification = e.modification
974
+ end
975
+ end
976
+ should "enable fixing by deleting both fields and renaming a box" do
977
+ action = @modification.actions[0]
978
+ begin
979
+ S::Schema.apply(action)
980
+ flunk("Deleting of field should not have resolved schema error")
981
+ rescue Spontaneous::SchemaModificationError => e
982
+ modification = e.modification
983
+ end
984
+ action = modification.actions[0]
985
+
986
+ begin
987
+ S::Schema.apply(action)
988
+ flunk("Deleting of field should not have resolved schema error")
989
+ rescue Spontaneous::SchemaModificationError => e
990
+ modification = e.modification
991
+ end
992
+ action = modification.actions[1]
993
+
994
+ begin
995
+ S::Schema.apply(action)
996
+ rescue Spontaneous::SchemaModificationError => e
997
+ flunk("Schema changes should have resolved error")
998
+ end
999
+ # p modification.actions
1000
+ end
1001
+ end
1002
+ end
1003
+
1004
+
1005
+ end
1006
+ end
1007
+ end
1008
+ end
1009
+