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,13 @@
1
+ <!DOCTYPE HTML>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>{{ title }} ­ <%= @domain %></title>
6
+ </head>
7
+ <body>
8
+
9
+ {% block :content %}
10
+ <h2>Welcome to <%= @domain %></h2>
11
+ {% endblock :content %}
12
+ </body>
13
+ </html>
@@ -0,0 +1,77 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'thor/group'
4
+
5
+ module Spontaneous
6
+ module Generators
7
+ class Site < Thor::Group
8
+ def self.available_dbs
9
+ %w(mysql postgres)
10
+ end
11
+
12
+ def self.source_root; File.expand_path(File.dirname(__FILE__) + "/site"); end
13
+ def self.banner; "spot generate site [domain]"; end
14
+
15
+ include Thor::Actions
16
+
17
+ class_option :root, :desc => "The root destination", :aliases => '-r', :default => ".", :type => :string
18
+ class_option :database, :desc => "The database to use ('mysql' (default) or 'postgres')", :aliases => '-d', :default => "mysql", :type => :string
19
+ class_option :dbpwd, :desc => "The password for the database root user", :aliases => '-p', :default => "", :type => :string
20
+
21
+ argument :domain, :type => :string, :desc => "The domain name of the site to generate"
22
+
23
+ desc "Generates a new site for DOMAIN"
24
+ def create_site
25
+ if self.class.available_dbs.include?(options.database)
26
+ @valid = true
27
+ say "Generating '#{domain}'...", :bold
28
+ @domain = domain
29
+ @site_name = domain.to_s.gsub(/\./, "_")
30
+ self.destination_root = options[:root]
31
+ empty_directory(@site_name)
32
+ self.destination_root = self.destination_root / @site_name
33
+ directory "config"
34
+ directory "schema"
35
+ directory "templates"
36
+ directory "public"
37
+ template "Gemfile.tt", "Gemfile"
38
+ template "Rakefile.tt", "Rakefile"
39
+ template "lib/site.rb.tt", "lib/site.rb"
40
+ empty_directory "lib/tasks"
41
+ empty_directory "log"
42
+ empty_directory "tmp"
43
+ empty_directory "cache/media/tmp"
44
+ empty_directory "cache/revisions"
45
+ copy_file ".gitignore"
46
+ template "lib/tasks/site.rake.tt", "lib/tasks/#{@site_name}.rake"
47
+ else
48
+ @valid = false
49
+ say "Invalid database selection '#{options.database}'. Valid options are: #{available_dbs.join(', ')}", :red
50
+ end
51
+ end
52
+
53
+ def finish_message
54
+ return unless @valid
55
+ message = (<<-MSG).gsub(/^ +/, '')
56
+
57
+
58
+ =========================================================
59
+
60
+ Site #{@domain} is ready.
61
+
62
+ To start using your new CMS do the following:
63
+ ---------------------------------------------------------
64
+ 1. cd #{options[:root]}/#{@site_name}
65
+ 2. bundle install
66
+ 3. spot init
67
+
68
+ Then go to http://spontaneouscms.org/docs
69
+ and read the many useful guides to getting started with Spontaneous.
70
+
71
+ MSG
72
+ say(message)
73
+ end
74
+ end # Site
75
+ end # Generators
76
+ end # Spontaneous
77
+
@@ -0,0 +1,23 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'thor/group'
4
+
5
+ module Spontaneous
6
+ module Generators
7
+ autoload :Site, "spontaneous/generators/site"
8
+ autoload :Page, "spontaneous/generators/page"
9
+ def self.available
10
+ self.constants.map { |c| self.const_get(c) }.select do |c|
11
+ c.ancestors.include?(Thor::Group)
12
+ end
13
+ end
14
+
15
+ class Generator < Thor::Group
16
+ def self.source_root; File.expand_path(File.dirname(__FILE__) + "/generators/#{self.name.demodulize.downcase}"); end
17
+
18
+ include Thor::Actions
19
+
20
+ class_option :root, :desc => "The root destination", :aliases => '-r', :default => ".", :type => :string
21
+ end
22
+ end # Generators
23
+ end # Spontaneous
@@ -0,0 +1,117 @@
1
+ # encoding: UTF-8
2
+
3
+ module Spontaneous
4
+ module ImageSize
5
+ def self.read(file)
6
+ reader = ImageReader.new(file)
7
+ reader.size
8
+ end
9
+
10
+ class ImageReader
11
+
12
+ def initialize(file)
13
+ if file.kind_of? IO
14
+ read_size(file)
15
+ else
16
+ File.open(file, 'rb') { |io| read_size(io) }
17
+ end
18
+
19
+ end
20
+
21
+ def read_size(file)
22
+ klass = image_type(file)
23
+ @image = klass.new(file)
24
+ end
25
+
26
+ def image_type(file)
27
+ img_top = file.read(16)
28
+ bytes = img_top.unpack("C*")
29
+ file.seek(0,0)
30
+ if img_top =~ /^GIF8[7,9]a/
31
+ Formats::GIF
32
+ elsif bytes[0, 8] == [137, 80, 78, 71, 13, 10, 26, 10]
33
+ Formats::PNG
34
+ elsif bytes[0, 2] == [255, 216]
35
+ Formats::JPEG
36
+ else
37
+ Formats::OTHER
38
+ end
39
+ end
40
+
41
+ def size
42
+ @image.size
43
+ end
44
+
45
+ module Formats
46
+ class Abstract
47
+ def initialize(file)
48
+ @file = file
49
+ def @file.read_o(length = 1, offset = nil)
50
+ self.seek(offset, 0) if offset
51
+ ret = self.read(length)
52
+ raise "cannot read!!" unless ret
53
+ ret
54
+ end
55
+ # read size straight away so that if file is closed we don't raise an error
56
+ @size = read_size
57
+ end
58
+ def size
59
+ @size
60
+ end
61
+
62
+ def read_size
63
+ [0,0]
64
+ end
65
+ end
66
+
67
+ class GIF < Abstract
68
+ def read_size
69
+ @file.read_o(6)
70
+ @file.read_o(4).unpack('vv')
71
+ end
72
+ end
73
+
74
+ class JPEG < Abstract
75
+ JPEGCodeCheck = [
76
+ "\xc0", "\xc1", "\xc2", "\xc3",
77
+ "\xc5", "\xc6", "\xc7",
78
+ "\xc9", "\xca", "\xcb",
79
+ "\xcd", "\xce", "\xcf",
80
+ ].map { |c| c.unpack('C').first }
81
+
82
+ def read_size
83
+ c_marker = 255 # Section marker.
84
+
85
+ @file.read_o(2)
86
+ while(true)
87
+ marker, code, length = @file.read_o(4).unpack('CCn')
88
+ raise "JPEG marker not found!" if marker != c_marker
89
+
90
+ if JPEGCodeCheck.include?(code)
91
+ height, width = @file.read_o(5).unpack('xnn')
92
+ return([width, height])
93
+ end
94
+ @file.read_o(length - 2)
95
+ end
96
+ end
97
+ end
98
+ class PNG < Abstract
99
+ def read_size
100
+ @file.read_o(12)
101
+ raise "This file is not PNG." unless @file.read_o(4) == "IHDR"
102
+ @file.read_o(8).unpack('NN')
103
+ end
104
+ end
105
+
106
+
107
+
108
+ class OTHER < Abstract
109
+ def read_size
110
+ [0,0]
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
117
+
@@ -0,0 +1,33 @@
1
+ # encoding: UTF-8
2
+
3
+ module Spontaneous
4
+ module JSON
5
+ module ModuleMethods
6
+ def parser
7
+ Yajl::Parser.new(:symbolize_keys => true)
8
+ end
9
+ def encoder
10
+ Yajl::Encoder.new
11
+ end
12
+
13
+ def parse(json_string)
14
+ parser.parse(json_string)
15
+ end
16
+
17
+ def encode(object)
18
+ encoder.encode(object)
19
+ end
20
+ end
21
+
22
+ extend ModuleMethods
23
+
24
+ def parse_json(json_string)
25
+ Spontaneous::JSON.parse(json_string)
26
+ end
27
+ alias_method :decode_json, :parse_json
28
+
29
+ def encode_json(object)
30
+ Spontaneous::JSON.encode(object)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,15 @@
1
+ # encoding: UTF-8
2
+
3
+ module Spontaneous
4
+ class Layout < Style
5
+ def try_paths
6
+ [["layouts", prototype.name.to_s]]
7
+ end
8
+
9
+ class Default < Layout
10
+ def try_paths
11
+ [["layouts", "standard"]]
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,280 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'active_support/ordered_hash'
4
+
5
+ module Spontaneous
6
+ OrderedHash = ActiveSupport::OrderedHash unless defined?(OrderedHash)
7
+
8
+ module Loader
9
+ class << self
10
+
11
+ def use_reloader?
12
+ Site.config.reload_classes
13
+ end
14
+
15
+ def load!
16
+ Reloader.run! if use_reloader?
17
+ Spontaneous.load_paths.each do |path|
18
+ load_classes(path)
19
+ end
20
+ end
21
+
22
+ def reload!
23
+ Reloader.reload!
24
+ end
25
+
26
+ # thank you oh makers of Merb for your genius
27
+ def load_classes(*paths)
28
+ orphaned_classes = []
29
+ paths.flatten.each do |path|
30
+ Dir[path].sort.each do |file|
31
+ begin
32
+ load_file(file)
33
+ rescue NameError => ne
34
+ # puts "Stashed file with missing requirements for later reloading: #{file}"
35
+ # ne.backtrace.each_with_index { |line, idx| puts "[#{idx}]: #{line}" }
36
+ orphaned_classes.unshift(file)
37
+ end
38
+ end
39
+ end
40
+ load_classes_with_requirements(orphaned_classes)
41
+ end
42
+
43
+ def load_file(file)
44
+ if use_reloader?
45
+ Reloader.safe_load(file)
46
+ else
47
+ require(file)
48
+ end
49
+ end
50
+
51
+ def load_classes_with_requirements(klasses)
52
+ klasses.uniq!
53
+
54
+ while klasses.size > 0
55
+ # Note size to make sure things are loading
56
+ size_at_start = klasses.size
57
+
58
+ # List of failed classes
59
+ failed_classes = []
60
+ # Map classes to exceptions
61
+ error_map = {}
62
+
63
+ klasses.each do |klass|
64
+ begin
65
+ load_file klass
66
+ rescue NameError => ne
67
+ error_map[klass] = ne
68
+ failed_classes.push(klass)
69
+ end
70
+ end
71
+ klasses.clear
72
+
73
+ # Keep list of classes unique
74
+ failed_classes.each { |k| klasses.push(k) unless klasses.include?(k) }
75
+
76
+ # Stop processing if nothing loads or if everything has loaded
77
+ if klasses.size == size_at_start && klasses.size != 0
78
+ # Write all remaining failed classes and their exceptions to the log
79
+ messages = error_map.map do |klass, e|
80
+ ["Could not load #{klass}:\n\n#{e.message} - (#{e.class})",
81
+ "#{(e.backtrace || []).join("\n")}"]
82
+ end
83
+ messages.each { |msg, trace| puts("#{msg}\n\n#{trace}") }
84
+ puts "#{failed_classes.join(", ")} failed to load."
85
+ end
86
+ break if(klasses.size == size_at_start || klasses.size == 0)
87
+ end
88
+
89
+ nil
90
+ end
91
+ end
92
+ module Reloader
93
+ class << self
94
+ CACHE = {}
95
+ MTIMES = {}
96
+ FILES_LOADED = {}
97
+ LOADED_CLASSES = {}
98
+
99
+ ##
100
+ # Reload all files with changes detected.
101
+ #
102
+ def reload!
103
+ rotation do |file, mtime|
104
+ # Retrive the last modified time
105
+ new_file = MTIMES[file].nil?
106
+ previous_mtime = MTIMES[file] ||= mtime
107
+ logger.debug "Detected a new file #{file}" if new_file
108
+ # We skip to next file if it is not new and not modified
109
+ next unless new_file || mtime > previous_mtime
110
+ # Now we can reload our file
111
+ safe_load(file, mtime)
112
+ end
113
+ end
114
+
115
+ ##
116
+ # Returns true if any file changes are detected and populates the MTIMES cache
117
+ #
118
+ def changed?
119
+ changed = false
120
+ rotation do |file, mtime|
121
+ new_file = MTIMES[file].nil?
122
+ previous_mtime = MTIMES[file] ||= mtime
123
+ changed = true if new_file || mtime > previous_mtime
124
+ end
125
+ changed
126
+ end
127
+ alias :run! :changed?
128
+
129
+ ##
130
+ # A safe Kernel::load which issues the necessary hooks depending on results
131
+ #
132
+ def safe_load(file, mtime=nil)
133
+ reload = mtime && mtime > MTIMES[file]
134
+
135
+ logger.debug "Reloading #{file}" if reload
136
+
137
+ # Removes all classes declared in the specified file
138
+ if klasses = LOADED_CLASSES.delete(file)
139
+ klasses.each { |klass| remove_constant(klass) }
140
+ end
141
+
142
+ # Keeps track of which constants were loaded and the files
143
+ # that have been added so that the constants can be removed
144
+ # and the files can be removed from $LOADED_FEAUTRES
145
+ if FILES_LOADED[file]
146
+ FILES_LOADED[file].each do |fl|
147
+ next if fl == file
148
+ $LOADED_FEATURES.delete(fl)
149
+ end
150
+ end
151
+
152
+ # Now reload the file ignoring any syntax errors
153
+ $LOADED_FEATURES.delete(file)
154
+
155
+ # Duplicate objects and loaded features in the file
156
+ klasses = ObjectSpace.classes.dup
157
+ files_loaded = $LOADED_FEATURES.dup
158
+
159
+ # Start to re-require old dependencies
160
+ #
161
+ # Why we need to reload the dependencies i.e. of a model?
162
+ #
163
+ # In some circumstances (i.e. with MongoMapper) reloading a model require:
164
+ #
165
+ # 1) Clean objectspace
166
+ # 2) Reload model dependencies
167
+ #
168
+ # We need to clean objectspace because for example we don't need to apply two times validations keys etc...
169
+ #
170
+ # We need to reload MongoMapper dependencies for re-initialize them.
171
+ #
172
+ # In other cases i.e. in a controller (specially with dependencies that uses autoload) reload stuff like sass
173
+ # is not really necessary... but how to distinguish when it is (necessary) since it is not?
174
+ #
175
+ if FILES_LOADED[file]
176
+ FILES_LOADED[file].each do |fl|
177
+ next if fl == file
178
+ # Swich off for a while warnings expecially "already initialized constant" stuff
179
+ begin
180
+ verbosity = $-v
181
+ $-v = nil
182
+ require(fl)
183
+ ensure
184
+ $-v = verbosity
185
+ end
186
+ end
187
+ end
188
+
189
+ # And finally reload the specified file
190
+ begin
191
+ require(file)
192
+ rescue SyntaxError => ex
193
+ logger.error "Cannot require #{file} because of syntax error: #{ex.message}"
194
+ ensure
195
+ MTIMES[file] = mtime if mtime
196
+ end
197
+
198
+ # Store the file details after successful loading
199
+ LOADED_CLASSES[file] = ObjectSpace.classes - klasses
200
+ FILES_LOADED[file] = $LOADED_FEATURES - files_loaded
201
+
202
+ nil
203
+ end
204
+
205
+ ##
206
+ # Removes the specified class and constant.
207
+ #
208
+ def remove_constant(const)
209
+ # return if Padrino::Reloader.exclude_constants.any? { |base| (const.to_s =~ /^#{base}/ || const.superclass.to_s =~ /^#{base}/) } &&
210
+ # !Padrino::Reloader.include_constants.any? { |base| (const.to_s =~ /^#{base}/ || const.superclass.to_s =~ /^#{base}/) }
211
+
212
+ Spontaneous::Schema.delete(const)
213
+
214
+ parts = const.to_s.split("::")
215
+ base = parts.size == 1 ? Object : Object.full_const_get(parts[0..-2].join("::"))
216
+ object = parts[-1].to_s
217
+ begin
218
+ base.send(:remove_const, object)
219
+ rescue NameError
220
+ end
221
+
222
+ nil
223
+ end
224
+
225
+ ##
226
+ # Searches Ruby files in your +Padrino.root+ and monitors them for any changes.
227
+ #
228
+ def rotation
229
+ paths = []
230
+ # paths = Dir[Padrino.root("*")].unshift(Padrino.root).
231
+ # reject { |path| Padrino::Reloader.exclude.include?(path) || !File.directory?(path) }
232
+ # files = paths.map { |path| Dir["#{path}/**/*.rb"] }.flatten.uniq
233
+
234
+ files = Spontaneous.load_paths.map do |glob|
235
+ Dir[glob]
236
+ end.flatten.uniq
237
+
238
+ files.map { |file|
239
+ # next if Padrino::Reloader.exclude.any? { |base| file =~ /^#{base}/ }
240
+
241
+ found, stat = figure_path(file, paths)
242
+ next unless found && stat && mtime = stat.mtime
243
+
244
+ CACHE[file] = found
245
+
246
+ yield(found, mtime)
247
+ }.compact
248
+ end
249
+
250
+ ##
251
+ # Takes a relative or absolute +file+ name and a couple possible +paths+ that
252
+ # the +file+ might reside in. Returns the full path and File::Stat for that path.
253
+ #
254
+ def figure_path(file, paths)
255
+ found = CACHE[file]
256
+ found = file if !found and Pathname.new(file).absolute?
257
+ found, stat = safe_stat(found)
258
+ return found, stat if found
259
+
260
+ # paths.find do |possible_path|
261
+ # path = ::File.join(possible_path, file)
262
+ # found, stat = safe_stat(path)
263
+ # return ::File.expand_path(found), stat if found
264
+ # end
265
+
266
+ return false, false
267
+ end
268
+
269
+ def safe_stat(file)
270
+ return unless file
271
+ stat = ::File.stat(file)
272
+ return file, stat if stat.file?
273
+ rescue Errno::ENOENT, Errno::ENOTDIR
274
+ CACHE.delete(file) and false
275
+ end
276
+ end # self
277
+
278
+ end
279
+ end # Loader
280
+ end # Spontaneous