spontaneous 0.2.0.beta1 → 0.2.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (335) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +24 -0
  3. data/.locat +42 -0
  4. data/.travis/gemfiles/Gemfile.empty +7 -0
  5. data/.travis.yml +18 -0
  6. data/Gemfile +12 -8
  7. data/LICENSE +1 -1
  8. data/Rakefile +15 -157
  9. data/Readme.markdown +1 -1
  10. data/application/css/core.css.scss +22 -146
  11. data/application/css/definitions.css.scss +7 -3
  12. data/application/css/dialogue.css.scss +26 -1
  13. data/application/css/editing.css.scss +70 -28
  14. data/application/css/font.css.scss +1 -1
  15. data/application/css/popover.css.scss +2 -0
  16. data/application/css/top.css.scss +231 -0
  17. data/application/js/add_alias_dialogue.js +1 -1
  18. data/application/js/add_home_dialogue.js +1 -1
  19. data/application/js/ajax.js +61 -31
  20. data/application/js/box.js +4 -4
  21. data/application/js/conflicted_field_dialogue.js +1 -1
  22. data/application/js/content.js +5 -5
  23. data/application/js/dom.js +5 -0
  24. data/application/js/edit_panel.js +1 -0
  25. data/application/js/editing.js +1 -1
  26. data/application/js/extensions.js +8 -0
  27. data/application/js/field/boolean.js +31 -0
  28. data/application/js/field/file.js +32 -4
  29. data/application/js/field/image.js +24 -9
  30. data/application/js/field/markdown.js +87 -59
  31. data/application/js/field/select.js +1 -1
  32. data/application/js/field/webvideo.js +6 -1
  33. data/application/js/init.js +2 -2
  34. data/application/js/jquery-selection-position.js +130 -0
  35. data/application/js/location.js +4 -25
  36. data/application/js/meta_view/user_admin.js +2 -2
  37. data/application/js/metadata.js +2 -2
  38. data/application/js/page_browser.js +1 -1
  39. data/application/js/panel/root_menu.js +0 -1
  40. data/application/js/popover.js +27 -12
  41. data/application/js/popover_view.js +20 -4
  42. data/application/js/preview.js +31 -16
  43. data/application/js/progress.js +22 -21
  44. data/application/js/publish.js +18 -7
  45. data/application/js/sharded_upload.js +9 -6
  46. data/application/js/spontaneous.js +3 -1
  47. data/application/js/top_bar.js +264 -173
  48. data/application/js/upload.js +12 -5
  49. data/application/js/upload_manager.js +4 -3
  50. data/application/js/user.js +1 -2
  51. data/application/js/views/box_view.js +1 -1
  52. data/application/js/views/page_view.js +16 -5
  53. data/application/js/views/piece_view.js +5 -4
  54. data/application/static/font/fontawesome-webfont-1c66a4738b40ef0f6b1abca0ba9a796d.ttf +0 -0
  55. data/application/views/index.erb +6 -14
  56. data/application/views/login.erb +6 -25
  57. data/application/views/schema_modification_error.html.erb +3 -7
  58. data/db/migrations/20130114120000_create_revision_tables.rb +2 -2
  59. data/db/migrations/20130813111009_increase_path_length.rb +14 -0
  60. data/gem-public_cert.pem +20 -0
  61. data/lib/spontaneous/asset/app_compiler.rb +44 -0
  62. data/lib/spontaneous/asset/environment.rb +225 -0
  63. data/lib/spontaneous/asset.rb +2 -67
  64. data/lib/spontaneous/box.rb +0 -1
  65. data/lib/spontaneous/capistrano/deploy.rb +2 -2
  66. data/lib/spontaneous/capistrano/sync.rb +1 -1
  67. data/lib/spontaneous/cli/init.rb +36 -13
  68. data/lib/spontaneous/cli/server.rb +0 -1
  69. data/lib/spontaneous/cli/site.rb +2 -1
  70. data/lib/spontaneous/cli.rb +3 -1
  71. data/lib/spontaneous/collections/entry_set.rb +4 -12
  72. data/lib/spontaneous/collections/hash_with_fallback.rb +20 -0
  73. data/lib/spontaneous/collections/prototype_set.rb +6 -5
  74. data/lib/spontaneous/crypt.rb +2 -2
  75. data/lib/spontaneous/data_mapper/content_model/associations.rb +115 -63
  76. data/lib/spontaneous/data_mapper.rb +1 -1
  77. data/lib/spontaneous/errors.rb +6 -0
  78. data/lib/spontaneous/extensions/object_space.rb +6 -0
  79. data/lib/spontaneous/facet.rb +1 -0
  80. data/lib/spontaneous/field/base.rb +86 -13
  81. data/lib/spontaneous/field/boolean.rb +65 -0
  82. data/lib/spontaneous/field/file.rb +17 -6
  83. data/lib/spontaneous/field/html.rb +13 -0
  84. data/lib/spontaneous/field/image/size.rb +76 -0
  85. data/lib/spontaneous/field/image.rb +99 -414
  86. data/lib/spontaneous/field/tags.rb +36 -0
  87. data/lib/spontaneous/field/update.rb +1 -1
  88. data/lib/spontaneous/field/webvideo/fallback.rb +41 -0
  89. data/lib/spontaneous/field/webvideo/vimeo.rb +113 -0
  90. data/lib/spontaneous/field/webvideo/vine.rb +94 -0
  91. data/lib/spontaneous/field/webvideo/youtube.rb +133 -0
  92. data/lib/spontaneous/field/webvideo.rb +100 -250
  93. data/lib/spontaneous/field.rb +1 -1
  94. data/lib/spontaneous/generators/site/Gemfile.tt +5 -14
  95. data/lib/spontaneous/generators/site/assets/README.md +20 -0
  96. data/lib/spontaneous/generators/site/assets/css/site.scss +8 -0
  97. data/lib/spontaneous/generators/site/assets/js/site.js +6 -0
  98. data/lib/spontaneous/generators/site/config/deploy.rb.tt +9 -0
  99. data/lib/spontaneous/generators/site/config/user_levels.yml +14 -3
  100. data/lib/spontaneous/generators/site/public/README.md +12 -0
  101. data/lib/spontaneous/generators/site/templates/layouts/standard.html.cut.tt +2 -2
  102. data/lib/spontaneous/generators/site.rb +77 -35
  103. data/lib/spontaneous/layout.rb +6 -7
  104. data/lib/spontaneous/loader.rb +21 -13
  105. data/lib/spontaneous/media/file.rb +22 -9
  106. data/lib/spontaneous/media/image/attributes.rb +33 -0
  107. data/lib/spontaneous/media/image/format/gif.rb +4 -0
  108. data/lib/spontaneous/media/image/format/jpg.rb +17 -0
  109. data/lib/spontaneous/media/image/format/png.rb +4 -0
  110. data/lib/spontaneous/media/image/format/webp.rb +26 -0
  111. data/lib/spontaneous/media/image/format.rb +79 -0
  112. data/lib/spontaneous/media/image/optimizer.rb +69 -0
  113. data/lib/spontaneous/media/image/processor.rb +17 -0
  114. data/lib/spontaneous/media/image/renderable.rb +52 -0
  115. data/lib/spontaneous/media/image/skeptick.rb +70 -0
  116. data/lib/spontaneous/media/image.rb +50 -0
  117. data/lib/spontaneous/media/temp_file.rb +4 -0
  118. data/lib/spontaneous/media.rb +1 -0
  119. data/lib/spontaneous/model/core/aliases.rb +14 -8
  120. data/lib/spontaneous/model/core/boxes.rb +5 -2
  121. data/lib/spontaneous/model/core/entries.rb +4 -0
  122. data/lib/spontaneous/model/core/entry.rb +1 -0
  123. data/lib/spontaneous/model/core/fields.rb +5 -2
  124. data/lib/spontaneous/model/core/locks.rb +16 -0
  125. data/lib/spontaneous/model/core/media.rb +1 -15
  126. data/lib/spontaneous/model/core.rb +31 -1
  127. data/lib/spontaneous/model/page/controllers.rb +2 -2
  128. data/lib/spontaneous/model/page/formats.rb +1 -4
  129. data/lib/spontaneous/model/page/layouts.rb +6 -2
  130. data/lib/spontaneous/model/page/locks.rb +8 -2
  131. data/lib/spontaneous/model/page/page_tree.rb +2 -2
  132. data/lib/spontaneous/model/page/paths.rb +74 -9
  133. data/lib/spontaneous/model/page.rb +11 -3
  134. data/lib/spontaneous/model.rb +6 -6
  135. data/lib/spontaneous/output/context/render_cache.rb +23 -0
  136. data/lib/spontaneous/output/context.rb +56 -30
  137. data/lib/spontaneous/output/helpers/script_helper.rb +9 -53
  138. data/lib/spontaneous/output/helpers/stylesheet_helper.rb +8 -40
  139. data/lib/spontaneous/output/template/renderer.rb +17 -5
  140. data/lib/spontaneous/output.rb +0 -1
  141. data/lib/spontaneous/paths.rb +6 -2
  142. data/lib/spontaneous/permissions/access_key.rb +18 -0
  143. data/lib/spontaneous/permissions/user.rb +1 -1
  144. data/lib/spontaneous/permissions.rb +4 -1
  145. data/lib/spontaneous/plugins/application/state.rb +19 -12
  146. data/lib/spontaneous/prototypes/field_prototype.rb +14 -8
  147. data/lib/spontaneous/published_revision.rb +7 -0
  148. data/lib/spontaneous/publishing/immediate.rb +43 -34
  149. data/lib/spontaneous/publishing/revision.rb +9 -6
  150. data/lib/spontaneous/rack/asset_server.rb +20 -0
  151. data/lib/spontaneous/rack/back/alias.rb +46 -0
  152. data/lib/spontaneous/rack/back/application_assets.rb +28 -0
  153. data/lib/spontaneous/rack/back/base.rb +34 -0
  154. data/lib/spontaneous/rack/back/changes.rb +19 -0
  155. data/lib/spontaneous/rack/back/content.rb +54 -0
  156. data/lib/spontaneous/rack/back/events.rb +38 -0
  157. data/lib/spontaneous/rack/back/field.rb +37 -0
  158. data/lib/spontaneous/rack/back/file.rb +118 -0
  159. data/lib/spontaneous/rack/back/helpers.rb +71 -0
  160. data/lib/spontaneous/rack/back/index.rb +16 -0
  161. data/lib/spontaneous/rack/back/login.rb +47 -0
  162. data/lib/spontaneous/rack/back/map.rb +24 -0
  163. data/lib/spontaneous/rack/back/page.rb +46 -0
  164. data/lib/spontaneous/rack/back/preview.rb +43 -0
  165. data/lib/spontaneous/rack/back/schema.rb +30 -0
  166. data/lib/spontaneous/rack/back/site.rb +25 -0
  167. data/lib/spontaneous/rack/back/site_assets.rb +13 -0
  168. data/lib/spontaneous/rack/back/unsupported_browser.rb +7 -0
  169. data/lib/spontaneous/rack/{user_admin.rb → back/user_admin.rb} +2 -5
  170. data/lib/spontaneous/rack/back.rb +85 -764
  171. data/lib/spontaneous/rack/cacheable_file.rb +3 -3
  172. data/lib/spontaneous/rack/front.rb +16 -9
  173. data/lib/spontaneous/rack/middleware/authenticate.rb +65 -0
  174. data/lib/spontaneous/rack/middleware/csrf.rb +66 -0
  175. data/lib/spontaneous/rack/middleware/reloader.rb +52 -0
  176. data/lib/spontaneous/rack/middleware/scope.rb +60 -0
  177. data/lib/spontaneous/rack/middleware.rb +6 -0
  178. data/lib/spontaneous/rack/page_controller.rb +18 -5
  179. data/lib/spontaneous/rack/public.rb +17 -11
  180. data/lib/spontaneous/rack.rb +34 -24
  181. data/lib/spontaneous/revision.rb +29 -2
  182. data/lib/spontaneous/schema/uid.rb +4 -3
  183. data/lib/spontaneous/schema/uid_map.rb +5 -24
  184. data/lib/spontaneous/schema.rb +1 -0
  185. data/lib/spontaneous/search/database.rb +8 -0
  186. data/lib/spontaneous/search/field.rb +1 -1
  187. data/lib/spontaneous/search/index.rb +3 -5
  188. data/lib/spontaneous/server.rb +1 -1
  189. data/lib/spontaneous/simultaneous.rb +1 -1
  190. data/lib/spontaneous/site/features.rb +4 -5
  191. data/lib/spontaneous/site/helpers.rb +22 -5
  192. data/lib/spontaneous/site/instance.rb +2 -2
  193. data/lib/spontaneous/site/selectors.rb +22 -3
  194. data/lib/spontaneous/storage/cloud.rb +13 -9
  195. data/lib/spontaneous/storage/local.rb +11 -6
  196. data/lib/spontaneous/style.rb +40 -23
  197. data/lib/spontaneous/utils/database/mysql_dumper.rb +1 -1
  198. data/lib/spontaneous/utils/smush_it.rb +1 -1
  199. data/lib/spontaneous/version.rb +1 -1
  200. data/lib/spontaneous.rb +35 -33
  201. data/spontaneous.gemspec +53 -787
  202. data/test/experimental/test_crypt.rb +56 -56
  203. data/test/experimental/test_features.rb +16 -27
  204. data/test/fixtures/assets/public1/css/data.css.scss +3 -0
  205. data/test/fixtures/assets/public1/css/image1.css.scss +4 -0
  206. data/test/fixtures/assets/public1/css/import.css.scss +1 -0
  207. data/test/fixtures/assets/public1/css/urlhash.css.scss +3 -0
  208. data/test/fixtures/assets/public1/js/a.js +1 -1
  209. data/test/fixtures/assets/public1/js/all.js +4 -0
  210. data/test/fixtures/assets/public1/js/{m.coffee → m.js.coffee} +1 -0
  211. data/test/fixtures/assets/public1/x.js +1 -0
  212. data/test/fixtures/assets/public2/css/all.css +4 -0
  213. data/test/fixtures/assets/public2/css/missing.css.scss +3 -0
  214. data/test/fixtures/assets/public2/i/y.png +0 -0
  215. data/test/fixtures/assets/public2/js/b.js +1 -1
  216. data/test/fixtures/assets/public2/js/c.js +1 -1
  217. data/test/fixtures/images/size.extended.webp +0 -0
  218. data/test/fixtures/images/size.lossless.webp +0 -0
  219. data/test/fixtures/images/size.lossy.webp +0 -0
  220. data/test/fixtures/schema/before.yml +4 -4
  221. data/test/fixtures/schema/schema.yml +1 -1
  222. data/test/fixtures/templates/aliases/aaa.html.cut +0 -0
  223. data/test/fixtures/templates/extended/partial_with_renderer.html.cut +1 -0
  224. data/test/fixtures/templates/extended/with_includes_and_renderer.html.cut +2 -0
  225. data/test/functional/test_application.rb +108 -106
  226. data/test/functional/test_back.rb +924 -930
  227. data/test/functional/test_front.rb +285 -238
  228. data/test/functional/test_user_manager.rb +75 -100
  229. data/test/integration/test_installation.rb +1 -1
  230. data/test/support/matchers.rb +12 -0
  231. data/test/support/minitest.rb +121 -0
  232. data/test/support/rack.rb +45 -0
  233. data/test/support/test_start_finish.rb +103 -0
  234. data/test/test_helper.rb +21 -68
  235. data/test/test_integration_helper.rb +1 -3
  236. data/test/unit/test_alias.rb +432 -408
  237. data/test/unit/test_asset_bundler.rb +58 -58
  238. data/test/unit/test_assets.rb +485 -155
  239. data/test/unit/test_async.rb +16 -37
  240. data/test/unit/test_authentication.rb +425 -457
  241. data/test/unit/test_boxes.rb +191 -191
  242. data/test/unit/test_changesets.rb +244 -254
  243. data/test/unit/test_config.rb +128 -142
  244. data/test/unit/test_content.rb +313 -359
  245. data/test/unit/test_content_inheritance.rb +29 -30
  246. data/test/unit/test_datamapper.rb +1205 -1080
  247. data/test/unit/test_datamapper_content.rb +49 -51
  248. data/test/unit/test_extensions.rb +23 -23
  249. data/test/unit/test_fields.rb +1488 -1180
  250. data/test/unit/test_formats.rb +158 -158
  251. data/test/unit/test_generators.rb +98 -40
  252. data/test/unit/test_helpers.rb +73 -76
  253. data/test/unit/test_image_size.rb +53 -22
  254. data/test/unit/test_images.rb +164 -165
  255. data/test/unit/test_layouts.rb +133 -122
  256. data/test/unit/test_logger.rb +14 -17
  257. data/test/unit/test_media.rb +69 -84
  258. data/test/unit/test_modifications.rb +513 -525
  259. data/test/unit/test_page.rb +462 -361
  260. data/test/unit/test_permissions.rb +379 -364
  261. data/test/unit/test_piece.rb +67 -75
  262. data/test/unit/test_plugins.rb +82 -89
  263. data/test/unit/test_prototype_set.rb +215 -216
  264. data/test/unit/test_prototypes.rb +114 -124
  265. data/test/unit/test_publishing.rb +252 -289
  266. data/test/unit/test_render.rb +167 -115
  267. data/test/unit/test_revisions.rb +436 -444
  268. data/test/unit/test_schema.rb +339 -309
  269. data/test/unit/test_search.rb +577 -574
  270. data/test/unit/test_serialisation.rb +136 -147
  271. data/test/unit/test_site.rb +252 -227
  272. data/test/unit/test_skeptick.rb +130 -0
  273. data/test/unit/test_storage.rb +46 -40
  274. data/test/unit/test_structure.rb +57 -66
  275. data/test/unit/test_styles.rb +104 -104
  276. data/test/unit/test_templates.rb +72 -57
  277. data/test/unit/test_type_hierarchy.rb +15 -16
  278. data/test/unit/test_visibility.rb +239 -257
  279. metadata +455 -326
  280. data/application/js/vendor/JS.Class-2.1.5/CHANGELOG +0 -283
  281. data/application/js/vendor/JS.Class-2.1.5/MIT-LICENSE +0 -30
  282. data/application/js/vendor/JS.Class-2.1.5/README +0 -30
  283. data/application/js/vendor/JS.Class-2.1.5/min/command.js +0 -1
  284. data/application/js/vendor/JS.Class-2.1.5/min/comparable.js +0 -1
  285. data/application/js/vendor/JS.Class-2.1.5/min/constant_scope.js +0 -1
  286. data/application/js/vendor/JS.Class-2.1.5/min/decorator.js +0 -1
  287. data/application/js/vendor/JS.Class-2.1.5/min/enumerable.js +0 -1
  288. data/application/js/vendor/JS.Class-2.1.5/min/forwardable.js +0 -1
  289. data/application/js/vendor/JS.Class-2.1.5/min/hash.js +0 -1
  290. data/application/js/vendor/JS.Class-2.1.5/min/linked_list.js +0 -1
  291. data/application/js/vendor/JS.Class-2.1.5/min/loader.js +0 -1
  292. data/application/js/vendor/JS.Class-2.1.5/min/method_chain.js +0 -1
  293. data/application/js/vendor/JS.Class-2.1.5/min/observable.js +0 -1
  294. data/application/js/vendor/JS.Class-2.1.5/min/package.js +0 -1
  295. data/application/js/vendor/JS.Class-2.1.5/min/proxy.js +0 -1
  296. data/application/js/vendor/JS.Class-2.1.5/min/ruby.js +0 -1
  297. data/application/js/vendor/JS.Class-2.1.5/min/set.js +0 -1
  298. data/application/js/vendor/JS.Class-2.1.5/min/stack_trace.js +0 -1
  299. data/application/js/vendor/JS.Class-2.1.5/min/state.js +0 -1
  300. data/application/js/vendor/JS.Class-2.1.5/min/stdlib.js +0 -16
  301. data/application/js/vendor/jquery-1.6.2.min.js +0 -18
  302. data/application/js/vendor/jquery-ui-1.8.16.custom.min.js +0 -791
  303. data/application/js/vendor/jquery-ui-1.8.9.custom.min.js +0 -415
  304. data/application/static/font/fontawesome-webfont-5c5c21100a346972a82c34c5e96ffcfe.ttf +0 -0
  305. data/application/static/select-arrow-6e7dd3745b00e934b0d7a3250c46558b.png +0 -0
  306. data/bin/limit-upload +0 -5
  307. data/bin/unlimit-upload +0 -3
  308. data/lib/spontaneous/asset/file.rb +0 -25
  309. data/lib/spontaneous/asset/source.rb +0 -28
  310. data/lib/spontaneous/image_size.rb +0 -123
  311. data/lib/spontaneous/output/assets/compression.rb +0 -58
  312. data/lib/spontaneous/output/assets.rb +0 -32
  313. data/lib/spontaneous/rack/around_back.rb +0 -20
  314. data/lib/spontaneous/rack/around_front.rb +0 -27
  315. data/lib/spontaneous/rack/around_preview.rb +0 -22
  316. data/lib/spontaneous/rack/assets.rb +0 -126
  317. data/lib/spontaneous/rack/authentication.rb +0 -20
  318. data/lib/spontaneous/rack/cookie_authentication.rb +0 -38
  319. data/lib/spontaneous/rack/helpers.rb +0 -52
  320. data/lib/spontaneous/rack/http.rb +0 -18
  321. data/lib/spontaneous/rack/media.rb +0 -30
  322. data/lib/spontaneous/rack/query_authentication.rb +0 -35
  323. data/lib/spontaneous/rack/reloader.rb +0 -45
  324. data/lib/spontaneous/rack/user_helpers.rb +0 -28
  325. /data/{README → application/js/field/markdown/text_command.js} +0 -0
  326. /data/application/js/vendor/{JS.Class-2.1.5/min/core.js → js.class-2.1.5.min.js} +0 -0
  327. /data/test/fixtures/assets/public1/css/{a.scss → a.css.scss} +0 -0
  328. /data/{lib/spontaneous/generators/site/public/css/site.scss → test/fixtures/assets/public1/x.css} +0 -0
  329. /data/{lib/spontaneous/generators/site/public/js/.empty_directory → test/fixtures/assets/public1/x.png} +0 -0
  330. /data/test/fixtures/assets/public2/css/{b.scss → b.css.scss} +0 -0
  331. /data/test/fixtures/assets/public2/js/{n.coffee → n.js.coffee} +0 -0
  332. /data/test/fixtures/back/{public → assets}/css/sass_include.scss +0 -0
  333. /data/test/fixtures/back/{public → assets}/css/sass_template.scss +0 -0
  334. /data/test/fixtures/back/{public → assets}/js/coffeescript.coffee +0 -0
  335. /data/{lib/spontaneous/generators/site/public/js/site.js → test/fixtures/templates/aliases/aa_alias.html.cut} +0 -0
@@ -6,9 +6,9 @@ module Spontaneous
6
6
  module Generators
7
7
  class Site < Thor::Group
8
8
  def self.available_dbs
9
- { "mysql" => { :gem => "mysql2", :adapter => "mysql2" },
10
- "postgresql" => { :gem => "pg", :adapter => "postgres" },
11
- "postgres" => { :gem => "pg", :adapter => "postgres" } }
9
+ postgres = { :gem => "pg", :adapter => "postgres", :user => nil }
10
+ { "mysql" => { :gem => "mysql2", :adapter => "mysql2", :user => "root" },
11
+ "pg" => postgres, "postgresql" => postgres, "postgres" => postgres }
12
12
  end
13
13
 
14
14
  def self.source_root; File.expand_path(File.dirname(__FILE__) + "/site"); end
@@ -18,53 +18,58 @@ module Spontaneous
18
18
 
19
19
  argument :domain, :type => :string, :desc => "The domain name of the site to generate"
20
20
 
21
- class_option :root, :desc => "The root destination", :aliases => '-r', :default => ".", :type => :string
22
- class_option :database, :desc => "The database to use ('mysql' (default) or 'postgres')", :aliases => %w(-d --db), :default => "mysql", :type => :string
23
- class_option :user, :desc => "The database account to use", :aliases => '-u', :default => "root", :type => :string
24
- class_option :password, :desc => "The password for the database user", :aliases => %w(-p), :default => "", :type => :string
25
- class_option :host, :desc => "The database host", :aliases => %w(-h), :default => "", :type => :string
21
+ class_option :root, :desc => "The root destination", :aliases => '-r', :default => ".", :type => :string
22
+ class_option :database, :desc => "The database to use ('postgres' (default) or 'mysql')", :aliases => %w(-d --db), :default => "postgres", :type => :string
23
+ class_option :user, :desc => "The database account to use", :aliases => '-u', :type => :string
24
+ class_option :password, :desc => "The password for the database user", :aliases => %w(-p), :default => "", :type => :string
25
+ class_option :host, :desc => "The database host", :aliases => %w(-h), :type => :string
26
26
 
27
27
 
28
28
  desc "Generates a new site for DOMAIN"
29
29
  def create_site
30
30
  if self.class.available_dbs.keys.include?(options.database)
31
- spec = Gem::Specification.load(File.expand_path("../../../../spontaneous.gemspec", __FILE__))
32
- adapter = self.class.available_dbs[options.database]
33
- adapter_dependency = spec.development_dependencies.detect { |dependency| dependency.name == adapter[:gem] }
34
- @valid = true
35
31
  say "Generating '#{domain}'...", :bold
36
- @domain = domain
32
+ @domain = domain
37
33
  @site_name = domain.to_s.gsub(/\./, "_")
38
34
  @username = domain.split(/\./).first
39
- @database = { :user => options.user, :adapter => adapter[:adapter], :gem => adapter_dependency, :password => options.password, :host => options.host }
35
+ @database = {
36
+ :user => options.user || adapter[:user],
37
+ :adapter => adapter[:adapter],
38
+ :gem => adapter_dependency,
39
+ :password => options.password,
40
+ :host => options.host
41
+ }
40
42
  self.destination_root = options[:root]
41
43
  empty_directory(@site_name)
42
44
  self.destination_root = self.destination_root / @site_name
43
- directory "config"
44
- directory "schema"
45
- directory "lib"
46
- directory "templates"
47
- directory "public"
48
- template "Gemfile.tt", "Gemfile"
49
- template "Capfile.tt", "Capfile"
50
- template "Rakefile.tt", "Rakefile"
51
- # template "lib/site.rb.tt", "lib/site.rb"
52
- # empty_directory "lib/tasks"
53
- empty_directory "log"
54
- empty_directory "tmp"
55
- empty_directory "cache/media"
56
- empty_directory "cache/tmp"
57
- empty_directory "cache/revisions"
58
- copy_file ".gitignore"
59
45
  # template "lib/tasks/site.rake.tt", "lib/tasks/#{@site_name}.rake"
60
46
  else
61
- @valid = false
62
47
  say "Invalid database selection '#{options.database}'. Valid options are: #{self.class.available_dbs.keys.join(', ')}", :red
48
+ exit 1
63
49
  end
64
50
  end
65
51
 
66
- def finish_message
67
- return unless @valid
52
+ def generate
53
+ directory "config"
54
+ directory "schema"
55
+ directory "lib"
56
+ directory "templates"
57
+ directory "assets"
58
+ directory "public"
59
+ template "Gemfile.tt", "Gemfile"
60
+ template "Capfile.tt", "Capfile"
61
+ template "Rakefile.tt", "Rakefile"
62
+ # template "lib/site.rb.tt", "lib/site.rb"
63
+ # empty_directory "lib/tasks"
64
+ empty_directory "log"
65
+ empty_directory "tmp"
66
+ empty_directory "cache/media"
67
+ empty_directory "cache/tmp"
68
+ empty_directory "cache/revisions"
69
+ copy_file ".gitignore"
70
+ end
71
+
72
+ def finish_message_1
68
73
  message = (<<-MSG).gsub(/^ +/, '')
69
74
 
70
75
 
@@ -72,21 +77,58 @@ module Spontaneous
72
77
 
73
78
  Site #{@domain} is ready.
74
79
 
80
+ MSG
81
+ say(message, :bold)
82
+ end
83
+
84
+ def finish_message_2
85
+ message = (<<-MSG).gsub(/^ +/, '')
75
86
  To start using your new CMS do the following:
76
87
  ---------------------------------------------------------
88
+ MSG
89
+ say(message)
90
+ end
91
+
92
+ def finish_message_3
93
+ message = (<<-MSG).gsub(/^ +/, '')
77
94
  1. cd #{options[:root]}/#{@site_name}
78
95
  2. bundle install
79
96
  3. spot init
97
+ MSG
98
+ say(message.chomp, :green)
99
+ end
100
+
101
+ def finish_message_4
102
+ message = (<<-MSG).gsub(/^ +/, '')
103
+ ---------------------------------------------------------
80
104
 
81
105
  Then go to
82
106
 
83
- http://spontaneous.io/documentation
107
+ http://spontaneous.io/
84
108
 
85
- and read the many useful guides to getting started with Spontaneous.
109
+ and read the many useful guides to getting started with
110
+ Spontaneous.
86
111
 
87
112
  MSG
88
113
  say(message)
89
114
  end
115
+
116
+ private
117
+
118
+ def adapter
119
+ self.class.available_dbs[options.database]
120
+ end
121
+
122
+ # Source adapter versions from Spontaneous's gemfile. This way
123
+ # sites are generated using the same version that tests are run against
124
+ def adapter_dependency
125
+ gemfile = (File.expand_path("../../../../Gemfile", __FILE__))
126
+ saved_gemfile, ENV['BUNDLE_GEMFILE'] = ENV['BUNDLE_GEMFILE'], gemfile
127
+ spec = Bundler::Dsl.new
128
+ spec.eval_gemfile(gemfile)
129
+ ENV['BUNDLE_GEMFILE'] = saved_gemfile
130
+ spec.dependencies.detect { |dependency| dependency.name == adapter[:gem] }
131
+ end
90
132
  end # Site
91
133
  end # Generators
92
134
  end # Spontaneous
@@ -17,16 +17,15 @@ module Spontaneous
17
17
  end
18
18
 
19
19
  class Anonymous
20
- def initialize(template_proc)
21
- @template_proc = template_proc
20
+ def initialize(templates = {})
21
+ @templates = templates
22
22
  end
23
23
 
24
24
  def template(format = :html)
25
- @template_proc
26
- end
27
-
28
- def exists?(format = :html)
29
- true
25
+ template = @templates[format]
26
+ # a layout without a format is used as a fallback
27
+ template ||= @templates[nil]
28
+ template
30
29
  end
31
30
 
32
31
  def name
@@ -1,10 +1,8 @@
1
1
  # encoding: UTF-8
2
2
 
3
- require 'active_support/ordered_hash'
3
+ require 'pathname'
4
4
 
5
5
  module Spontaneous
6
- OrderedHash = ActiveSupport::OrderedHash unless defined?(OrderedHash)
7
-
8
6
  class Loader
9
7
  attr_reader :use_reloader, :load_paths
10
8
 
@@ -110,7 +108,7 @@ module Spontaneous
110
108
  @cache = {}
111
109
  @mtimes = {}
112
110
  @files_loaded = {}
113
- @loaded_classes = {}
111
+ @loaded_classes = Hash.new { |h, k| h[k] = [] }
114
112
  end
115
113
 
116
114
  def reset!
@@ -167,7 +165,7 @@ module Spontaneous
167
165
  def safe_load(file, mtime=nil)
168
166
  reload = mtime && mtime > mtimes[file]
169
167
 
170
- logger.debug "Reloading #{file}" if reload
168
+ logger.debug "Reloading #{relativize_path(file)}" if reload
171
169
 
172
170
  # Removes all classes declared in the specified file
173
171
  if klasses = loaded_classes.delete(file)
@@ -189,6 +187,7 @@ module Spontaneous
189
187
 
190
188
  # Duplicate objects and loaded features in the file
191
189
  klasses = ObjectSpace.classes.dup
190
+ modules = ObjectSpace.modules.dup
192
191
  already_loaded = $LOADED_FEATURES.dup
193
192
 
194
193
  # Start to re-require old dependencies
@@ -224,24 +223,35 @@ module Spontaneous
224
223
  # And finally reload the specified file
225
224
  begin
226
225
  require(file)
227
- # rescue => ex
228
- # logger.fatal "Cannot require #{file}\\\\\\\\n#{ex.message}"
229
- # raise ex
226
+ rescue => e
227
+ # logger.info "Failed to load '#{relativize_path(file)}' : #{e.message}"
228
+ raise e
230
229
  ensure
230
+ # Ensure that any classes loaded by the file before it failed get
231
+ # added to the list of loaded classes for a file.
232
+ # Without this a long file with an error will only record classes
233
+ # loaded after the error has been resolved.
234
+ new_objects = (ObjectSpace.classes - klasses) + (ObjectSpace.modules - modules)
235
+ loaded_classes[file].concat(new_objects)
231
236
  mtimes[file] = mtime if mtime
232
237
  end
233
238
 
234
239
  # Store the file details after successful loading
235
- loaded_classes[file] = ObjectSpace.classes - klasses
236
240
  self.files_loaded[file] = $LOADED_FEATURES - already_loaded
237
241
 
238
- nil
242
+ loaded_classes[file]
243
+ end
244
+
245
+ def relativize_path(path)
246
+ pwd = Pathname.new(Dir.pwd)
247
+ Pathname.new(path).relative_path_from(pwd)
239
248
  end
240
249
 
241
250
  ##
242
251
  # Removes the specified class and constant.
243
252
  #
244
253
  def remove_constant(const)
254
+ const.__finalize if const.respond_to?(:__finalize)
245
255
  Spontaneous.schema.delete(const)
246
256
 
247
257
  parts = const.to_s.split("::")
@@ -379,9 +389,7 @@ module Spontaneous
379
389
  end
380
390
 
381
391
  def remove_constant(const)
382
- if is_schema_class?(const)
383
- super
384
- end
392
+ super if is_schema_class?(const)
385
393
  end
386
394
 
387
395
  def dependency_file?(file)
@@ -8,36 +8,51 @@ module Spontaneous::Media
8
8
 
9
9
  attr_reader :filename, :owner, :source
10
10
 
11
- def initialize(owner, filename, mimetype = nil)
12
- @owner, @filename, @mimetype = owner, Spontaneous::Media.to_filename(filename), mimetype
11
+ def initialize(owner, filename, headers = {})
12
+ headers = { content_type: headers } if headers.is_a?(String)
13
+ @owner, @filename, @headers = owner, Spontaneous::Media.to_filename(filename), headers
13
14
  end
14
15
 
16
+ # Create a new File instance with a new name.
17
+ # This new file instance should take its content type from the new name
18
+ # because one of the uses of this is during image size creation where we
19
+ # might be converting from one format to another.
15
20
  def rename(new_filename)
16
- self.class.new(owner, new_filename, nil)
21
+ headers = storage_headers
22
+ headers.delete(:content_type)
23
+ self.class.new(owner, new_filename, headers)
17
24
  end
18
25
 
19
26
  def open(mode = 'wb', &block)
20
- storage.open(storage_path, mimetype, mode, &block)
27
+ storage.open(storage_path, storage_headers, mode, &block)
21
28
  end
22
29
 
23
30
  def copy(existing_file)
24
31
  @source = existing_file.respond_to?(:path) ? existing_file.path : existing_file
25
- storage.copy(existing_file, storage_path, mimetype)
32
+ storage.copy(existing_file, storage_path, storage_headers)
26
33
  self
27
34
  end
28
35
 
36
+ def storage_headers
37
+ headers = @headers.dup
38
+ headers[:content_type] ||= mimetype
39
+ headers
40
+ end
41
+
29
42
  def url
30
43
  storage.public_url(storage_path)
31
44
  end
32
45
 
33
46
  def mimetype
34
- @mimetype ||= ::Rack::Mime.mime_type(ext)
47
+ @mimetype ||= ( @headers[:content_type] || ::Rack::Mime.mime_type(ext) )
35
48
  end
36
49
 
37
50
  def ext
38
51
  F.extname(filename)
39
52
  end
40
53
 
54
+ alias_method :extname, :ext
55
+
41
56
  def filesize
42
57
  F.size(source)
43
58
  end
@@ -78,10 +93,8 @@ module Spontaneous::Media
78
93
  F.join(storage.root, media_dir)
79
94
  end
80
95
 
81
- alias_method :filepath, :path
82
-
83
96
  def serialize
84
- { :url => url, :mimetype => mimetype, :path => path, :filename => filename }
97
+ { :url => url, :type => mimetype, :filename => filename }
85
98
  end
86
99
  end
87
100
  end
@@ -0,0 +1,33 @@
1
+ module Spontaneous::Media
2
+ module Image
3
+ class Attributes
4
+ include Renderable
5
+
6
+ attr_reader :src, :width, :height, :filesize, :filepath
7
+
8
+ def initialize(params={})
9
+ params ||= {}
10
+ @src, @width, @height, @filesize, @filepath = params.values_at(:src, :width, :height, :filesize, :path)
11
+ end
12
+
13
+ def serialize
14
+ { :src => src, :width => width, :height => height, :filesize => filesize }
15
+ end
16
+
17
+ def inspect
18
+ %(<#{self.class.name}: src=#{src.inspect} width="#{width}" height="#{height}">)
19
+ end
20
+
21
+ def blank?
22
+ src.blank?
23
+ end
24
+
25
+ # Will only work for files in local storage
26
+ def filepath
27
+ Spontaneous::Media.to_filepath(src)
28
+ end
29
+
30
+ alias_method :empty?, :blank?
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,4 @@
1
+ Spontaneous::Media::Image.define :gif, [71, 73, 70, 56] do |file|
2
+ file.seek(6)
3
+ file.read(4).unpack('vv')
4
+ end
@@ -0,0 +1,17 @@
1
+ Spontaneous::Media::Image.define :jpg, [255, 216] do |file|
2
+ markers = [192, 193, 194, 195, 197, 198, 199, 201, 202, 203, 205, 206, 207]
3
+ height = width = 0
4
+ c_marker = 255 # Section marker.
5
+ file.seek(2)
6
+ while(true)
7
+ marker, code, length = file.read(4).unpack('CCn')
8
+ raise "Invalid JPG file: marker not found! '#{file.path}'" if marker != c_marker
9
+
10
+ if markers.include?(code)
11
+ height, width = file.read(5).unpack('xnn')
12
+ break
13
+ end
14
+ file.seek(length - 2, IO::SEEK_CUR)
15
+ end
16
+ [width, height]
17
+ end
@@ -0,0 +1,4 @@
1
+ Spontaneous::Media::Image.define :png, [137, 80, 78, 71, 13, 10, 26, 10] do |file|
2
+ file.seek(16)
3
+ file.read(8).unpack('NN')
4
+ end
@@ -0,0 +1,26 @@
1
+ Spontaneous::Media::Image.define :webp, [82, 73, 70, 70, nil, nil, nil, nil, 87, 69, 66, 80] do |file|
2
+ file.seek(12)
3
+ format = file.read(4)
4
+ height = width = 0
5
+ uint24 = proc { |bytes| (bytes + 0.chr).unpack("V").first }
6
+ uint14 = proc { |int| int & 0x3fff }
7
+
8
+ case format
9
+ when "VP8 " #simple-file-format-lossy
10
+ file.seek(10, IO::SEEK_CUR)
11
+ # two 14 bit ints with 2 bits of scaling info
12
+ header = file.read(4).unpack("v*")
13
+ width, height = header.map(&uint14)
14
+ when "VP8L" #simple-file-format-lossless
15
+ file.seek(5, IO::SEEK_CUR)
16
+ # two consecutive 14 bit ints
17
+ header = file.read(4).unpack("v*")
18
+ width = uint14[header[0]] + 1
19
+ height = (header[0] >> 14) + ((header[1] & 0xfff) << 2) + 1
20
+ when "VP8X" #extended-file-format
21
+ file.seek(8, IO::SEEK_CUR)
22
+ width = uint24[file.read(3)] + 1
23
+ height = uint24[file.read(3)] + 1
24
+ end
25
+ [width, height]
26
+ end
@@ -0,0 +1,79 @@
1
+ module Spontaneous::Media::Image
2
+ class Format
3
+ def initialize(image, attributes = nil)
4
+ @image, @attributes = image, attributes
5
+ end
6
+
7
+ def format
8
+ attributes[:format]
9
+ end
10
+
11
+ def dimensions
12
+ attributes[:dimensions]
13
+ end
14
+
15
+ def size
16
+ attributes[:filesize]
17
+ end
18
+
19
+ def src
20
+ [:src, :path].each do |m|
21
+ return @image.send(m) if @image.respond_to?(m)
22
+ end
23
+ @image
24
+ end
25
+
26
+ def attributes
27
+ @attributes ||= read_attributes
28
+ end
29
+
30
+ def serialize
31
+ attributes.merge(:format => format.to_s)
32
+ end
33
+
34
+ def inspect
35
+ %(#<Spontaneous::Media::Image::#{format.to_s.upcase} #{size}B #{dimensions.join("x")} #{src}>)
36
+ end
37
+
38
+ private
39
+
40
+ def read_attributes
41
+ open do |file|
42
+ analyze(file)
43
+ end
44
+ end
45
+
46
+ def analyze(file)
47
+ size = file.size
48
+ return to_attributes(nil) if size == 0
49
+ header = Spontaneous::Media::Image.peek(file)
50
+ file.rewind
51
+ Spontaneous::Media::Image.formats.each do |format, (magic, dim)|
52
+ bytes = header[0, magic.length].zip(magic)
53
+ if bytes.all? { |b, m| m.nil? || b == m }
54
+ return to_attributes(format, size, dim.call(file))
55
+ end
56
+ end
57
+ to_attributes(:unknown, size)
58
+ end
59
+
60
+ def to_attributes(format, size = 0, dimensions = [0,0])
61
+ { :format => format, :filesize => size, :dimensions => dimensions,
62
+ :width => dimensions[0], :height => dimensions[1] }
63
+ end
64
+
65
+ def open(&block)
66
+ if @image.respond_to?(:read) # IO
67
+ yield @image
68
+ elsif @image.respond_to?(:open) # Media::File
69
+ @image.open do |file|
70
+ block.call(file)
71
+ end
72
+ else # Probably string
73
+ File.open(@image, 'rb') do |file|
74
+ block.call(file)
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,69 @@
1
+ require 'shellwords'
2
+
3
+ module Spontaneous::Media::Image
4
+ class Optimizer
5
+ def self.run(source_image)
6
+ self.new(source_image).run
7
+ end
8
+
9
+ def self.binary(cmd)
10
+ (@binaries ||={})[cmd] ||= find_binary(cmd)
11
+ end
12
+
13
+ def self.find_binary(name)
14
+ binary = `which #{name}`.chomp
15
+ return nil if binary.length == 0
16
+ binary
17
+ end
18
+
19
+ def initialize(source_image)
20
+ @image = source_image
21
+ end
22
+
23
+ def run
24
+ format = Spontaneous::Media::Image.format(@image)
25
+ if respond_to?(format)
26
+ send(format)
27
+ end
28
+ end
29
+
30
+ def jpg
31
+ run_optimization("jpegoptim", "-o -q --strip-all --preserve --force #{@image} 2>&1 1>/dev/null")
32
+ # run_optimization("jpegtran", "-optimize -progressive -copy none -outfile #{input} #{input}")
33
+ end
34
+
35
+ def png
36
+ # pngcrush refuses to play if the input & output are the same
37
+ Tempfile.open("crushme", :binmode => true) do |temp|
38
+ ::File.open(@image, "rb") { |src| IO.copy_stream(src, temp) }
39
+ run_optimization("pngcrush", "-rem alla -reduce -cc #{temp.path} #{@image}")
40
+ end
41
+ end
42
+
43
+ def run_optimization(lib, args)
44
+ exe = binary(lib)
45
+ return unless exe
46
+ command = [exe, args].join(" ")
47
+ logger.debug(command)
48
+ measure do
49
+ process = POSIX::Spawn::Child.new(command)
50
+ unless process.success?
51
+ logger.error("Error optimizing image: #{@image}\n#{process.err}")
52
+ end
53
+ process.status
54
+ end
55
+ end
56
+
57
+ def measure
58
+ before, start = ::File.size(@image), Time.now
59
+ result = yield
60
+ after, _end = ::File.size(@image), Time.now
61
+ logger.debug("#{(100 * (1 - after.to_f/before.to_f)).round(1)}% optimization of '#{::File.basename(@image)}' [#{before} -> #{after}] in #{_end - start}s")
62
+ result
63
+ end
64
+
65
+ def binary(cmd)
66
+ self.class.binary(cmd)
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,17 @@
1
+ module Spontaneous::Media::Image
2
+ class Processor
3
+ include Spontaneous::Media::Image::Skeptick
4
+
5
+ def initialize(input, output)
6
+ @input, @output = input, output
7
+ end
8
+
9
+ def apply(process)
10
+ cmd = convert(@input, :to => @output, &process)
11
+ cmd.run
12
+ end
13
+
14
+ def optimize!
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,52 @@
1
+
2
+ module Spontaneous::Media::Image
3
+ module Renderable
4
+ attr_accessor :template_params
5
+
6
+ def render(format=:html, *args)
7
+ case format
8
+ when "html", :html
9
+ to_html(*args)
10
+ else
11
+ value
12
+ end
13
+ end
14
+
15
+ def to_html(attr={})
16
+ default_attr = {
17
+ :src => src,
18
+ :width => width,
19
+ :height => height,
20
+ :alt => ""
21
+ }
22
+ default_attr.delete(:width) if width.nil?
23
+ default_attr.delete(:height) if height.nil?
24
+ if template_params && template_params.length > 0 && template_params[0].is_a?(Hash)
25
+ attr = template_params[0].merge(attr)
26
+ end
27
+ if attr.key?(:width) || attr.key?(:height)
28
+ default_attr.delete(:width)
29
+ default_attr.delete(:height)
30
+ if (attr.key?(:width) && !attr[:width]) || (attr.key?(:height) && !attr[:height])
31
+ attr.delete(:width)
32
+ attr.delete(:height)
33
+ end
34
+ end
35
+ attr = default_attr.merge(attr)
36
+ params = []
37
+ attr.each do |name, value|
38
+ params << %(#{name}="#{value.to_s.escape_html}")
39
+ end
40
+ %(<img #{params.join(' ')} />)
41
+ end
42
+
43
+ def to_s
44
+ src
45
+ end
46
+
47
+ def /(value)
48
+ return value if self.blank?
49
+ self
50
+ end
51
+ end
52
+ end