landable 1.7.0

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 (310) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/CHANGELOG.md +5 -0
  4. data/Gemfile +15 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.md +56 -0
  7. data/Rakefile +22 -0
  8. data/app/controllers/concerns/landable/variables_concern.rb +38 -0
  9. data/app/controllers/landable/api/access_tokens_controller.rb +48 -0
  10. data/app/controllers/landable/api/assets_controller.rb +55 -0
  11. data/app/controllers/landable/api/categories_controller.rb +13 -0
  12. data/app/controllers/landable/api/directories_controller.rb +19 -0
  13. data/app/controllers/landable/api/page_revisions_controller.rb +38 -0
  14. data/app/controllers/landable/api/pages_controller.rb +96 -0
  15. data/app/controllers/landable/api/templates_controller.rb +33 -0
  16. data/app/controllers/landable/api/themes_controller.rb +57 -0
  17. data/app/controllers/landable/api_controller.rb +75 -0
  18. data/app/controllers/landable/application_controller.rb +4 -0
  19. data/app/controllers/landable/public/pages_controller.rb +25 -0
  20. data/app/controllers/landable/public/preview/page_revisions_controller.rb +16 -0
  21. data/app/controllers/landable/public/preview/pages_controller.rb +16 -0
  22. data/app/controllers/landable/public/sitemap_controller.rb +18 -0
  23. data/app/decorators/landable/null_page_decorator.rb +26 -0
  24. data/app/decorators/landable/page_decorator.rb +40 -0
  25. data/app/helpers/landable/application_helper.rb +13 -0
  26. data/app/helpers/landable/pages_helper.rb +20 -0
  27. data/app/models/concerns/landable/has_assets.rb +74 -0
  28. data/app/models/concerns/landable/table_name.rb +12 -0
  29. data/app/models/concerns/landable/traffic/table_name.rb +14 -0
  30. data/app/models/landable/access_token.rb +20 -0
  31. data/app/models/landable/asset.rb +63 -0
  32. data/app/models/landable/asset_search_engine.rb +20 -0
  33. data/app/models/landable/author.rb +12 -0
  34. data/app/models/landable/category.rb +27 -0
  35. data/app/models/landable/directory.rb +23 -0
  36. data/app/models/landable/page.rb +259 -0
  37. data/app/models/landable/page_revision.rb +74 -0
  38. data/app/models/landable/page_search_engine.rb +20 -0
  39. data/app/models/landable/search_engine.rb +39 -0
  40. data/app/models/landable/template.rb +24 -0
  41. data/app/models/landable/theme.rb +20 -0
  42. data/app/models/landable/traffic/access.rb +11 -0
  43. data/app/models/landable/traffic/ad_group.rb +11 -0
  44. data/app/models/landable/traffic/ad_type.rb +11 -0
  45. data/app/models/landable/traffic/attribution.rb +38 -0
  46. data/app/models/landable/traffic/bid_match_type.rb +11 -0
  47. data/app/models/landable/traffic/browser.rb +11 -0
  48. data/app/models/landable/traffic/campaign.rb +11 -0
  49. data/app/models/landable/traffic/city.rb +11 -0
  50. data/app/models/landable/traffic/content.rb +11 -0
  51. data/app/models/landable/traffic/cookie.rb +16 -0
  52. data/app/models/landable/traffic/country.rb +11 -0
  53. data/app/models/landable/traffic/creative.rb +11 -0
  54. data/app/models/landable/traffic/device.rb +11 -0
  55. data/app/models/landable/traffic/device_type.rb +11 -0
  56. data/app/models/landable/traffic/domain.rb +12 -0
  57. data/app/models/landable/traffic/event.rb +12 -0
  58. data/app/models/landable/traffic/event_type.rb +11 -0
  59. data/app/models/landable/traffic/experiment.rb +11 -0
  60. data/app/models/landable/traffic/http_method.rb +11 -0
  61. data/app/models/landable/traffic/ip_address.rb +11 -0
  62. data/app/models/landable/traffic/ip_lookup.rb +12 -0
  63. data/app/models/landable/traffic/keyword.rb +11 -0
  64. data/app/models/landable/traffic/location.rb +11 -0
  65. data/app/models/landable/traffic/match_type.rb +11 -0
  66. data/app/models/landable/traffic/medium.rb +11 -0
  67. data/app/models/landable/traffic/mime_type.rb +11 -0
  68. data/app/models/landable/traffic/network.rb +11 -0
  69. data/app/models/landable/traffic/owner.rb +10 -0
  70. data/app/models/landable/traffic/ownership.rb +10 -0
  71. data/app/models/landable/traffic/page_view.rb +24 -0
  72. data/app/models/landable/traffic/path.rb +13 -0
  73. data/app/models/landable/traffic/placement.rb +11 -0
  74. data/app/models/landable/traffic/platform.rb +11 -0
  75. data/app/models/landable/traffic/position.rb +11 -0
  76. data/app/models/landable/traffic/query_string.rb +12 -0
  77. data/app/models/landable/traffic/referer.rb +11 -0
  78. data/app/models/landable/traffic/region.rb +11 -0
  79. data/app/models/landable/traffic/search_term.rb +11 -0
  80. data/app/models/landable/traffic/source.rb +11 -0
  81. data/app/models/landable/traffic/target.rb +11 -0
  82. data/app/models/landable/traffic/user_agent.rb +28 -0
  83. data/app/models/landable/traffic/user_agent_type.rb +11 -0
  84. data/app/models/landable/traffic/visit.rb +15 -0
  85. data/app/models/landable/traffic/visitor.rb +13 -0
  86. data/app/responders/landable/api_responder.rb +76 -0
  87. data/app/responders/landable/page_render_responder.rb +15 -0
  88. data/app/serializers/landable/access_token_serializer.rb +6 -0
  89. data/app/serializers/landable/asset_serializer.rb +14 -0
  90. data/app/serializers/landable/author_serializer.rb +5 -0
  91. data/app/serializers/landable/category_serializer.rb +5 -0
  92. data/app/serializers/landable/directory_serializer.rb +8 -0
  93. data/app/serializers/landable/page_revision_serializer.rb +15 -0
  94. data/app/serializers/landable/page_serializer.rb +31 -0
  95. data/app/serializers/landable/template_serializer.rb +5 -0
  96. data/app/serializers/landable/theme_serializer.rb +7 -0
  97. data/app/services/landable/authentication_service.rb +44 -0
  98. data/app/services/landable/registration_service.rb +13 -0
  99. data/app/services/landable/render_service.rb +86 -0
  100. data/app/services/landable/tidy_service.rb +155 -0
  101. data/app/uploaders/landable/asset_uploader.rb +9 -0
  102. data/app/validators/path_validator.rb +12 -0
  103. data/app/validators/url_validator.rb +13 -0
  104. data/app/views/templates/preview.liquid +122 -0
  105. data/bin/rails +8 -0
  106. data/bin/redb +7 -0
  107. data/config.ru +7 -0
  108. data/config/cucumber.yml +5 -0
  109. data/config/routes.rb +62 -0
  110. data/db/migrate/20130510221424_create_landable_schema.rb +338 -0
  111. data/db/migrate/20130909182713_landable_pages__add_updated_by.rb +11 -0
  112. data/db/migrate/20130909182715_landable_page_revisions__break_out_snapshot.rb +72 -0
  113. data/db/migrate/20130909191153_landable_pages__add_lock_version.rb +5 -0
  114. data/db/migrate/20131002220041_file_based_themes.rb +12 -0
  115. data/db/migrate/20131008164204_create_head_tag_on_page.rb +19 -0
  116. data/db/migrate/20131008193544_drop_status_codes_model.rb +44 -0
  117. data/db/migrate/20131028145652_add_traffic_schema.rb +276 -0
  118. data/db/migrate/20131101213623_add_dnt_column_to_visits.rb +7 -0
  119. data/db/migrate/20131104224120_add_meta_on_events.rb +7 -0
  120. data/db/migrate/20131106185946_add_index_on_page_revisions_path.rb +6 -0
  121. data/db/migrate/20131106193021_page_revisisons__path_status_code_index.rb +9 -0
  122. data/db/migrate/20131108212501_traffic_owner_ids_are_serials.rb +20 -0
  123. data/db/migrate/20131121150902_add_attribution_id_to_unique_index.rb +10 -0
  124. data/db/migrate/20131216214027_drop_browser_screenshot_tables.rb +6 -0
  125. data/db/migrate/20140128170659_file_backed_templates.rb +8 -0
  126. data/db/migrate/20140205193757_fix_status_codes.rb +24 -0
  127. data/db/migrate/20140206211322_add_response_time_to_traffic_page_views.rb +7 -0
  128. data/db/migrate/20140220170324_add_slug_to_categories.rb +14 -0
  129. data/db/migrate/20140220174630_add_abstract_and_hero_asset_to_pages_and_page_revisions.rb +8 -0
  130. data/db/migrate/20140224205516_rename_traffic_schema.rb +40 -0
  131. data/db/pgtap/pgtap.sql +9034 -0
  132. data/db/test/landable.access_tokens.sql +13 -0
  133. data/db/test/landable.assets.sql +16 -0
  134. data/db/test/landable.authors.sql +22 -0
  135. data/db/test/landable.categories.sql +9 -0
  136. data/db/test/landable.page_revisions.sql +41 -0
  137. data/db/test/landable.pages.sql +19 -0
  138. data/db/test/landable.templates.sql +15 -0
  139. data/db/test/landable.themes.sql +25 -0
  140. data/doc/schema/access_token.json +22 -0
  141. data/doc/schema/asset.json +65 -0
  142. data/doc/schema/author.json +30 -0
  143. data/doc/schema/directory.json +24 -0
  144. data/doc/schema/page.json +95 -0
  145. data/doc/schema/page_revision.json +70 -0
  146. data/doc/schema/theme.json +37 -0
  147. data/doc/schema/uuid.json +6 -0
  148. data/features/api/access_tokens.feature +84 -0
  149. data/features/api/assets.feature +46 -0
  150. data/features/api/cors.feature +25 -0
  151. data/features/api/pages.feature +42 -0
  152. data/features/api/preview.feature +16 -0
  153. data/features/api/templates.feature +33 -0
  154. data/features/api/themes.feature +33 -0
  155. data/features/liquid/body.feature +35 -0
  156. data/features/liquid/drops/categories.feature +54 -0
  157. data/features/liquid/tags.feature +168 -0
  158. data/features/public/content_types.feature +17 -0
  159. data/features/public/publishing.feature +45 -0
  160. data/features/public/status_codes.feature +25 -0
  161. data/features/public/views.feature +17 -0
  162. data/features/step_definitions/asset_steps.rb +60 -0
  163. data/features/step_definitions/core_api_steps.rb +139 -0
  164. data/features/step_definitions/debug_steps.rb +3 -0
  165. data/features/step_definitions/factory_steps.rb +124 -0
  166. data/features/step_definitions/html_steps.rb +9 -0
  167. data/features/step_definitions/liquid_steps.rb +79 -0
  168. data/features/step_definitions/revision_steps.rb +5 -0
  169. data/features/step_definitions/theme_steps.rb +43 -0
  170. data/features/support/env.rb +66 -0
  171. data/features/support/usefulness.rb +13 -0
  172. data/landable.gemspec +54 -0
  173. data/lib/generators/landable/collection/collection_generator.rb +0 -0
  174. data/lib/generators/landable/collection/templates/stylesheets/landable/%file_name%.less +0 -0
  175. data/lib/generators/landable/collection/templates/stylesheets/landable/%file_name%/mixins.less +0 -0
  176. data/lib/generators/landable/collection/templates/stylesheets/landable/%file_name%/variables.less +0 -0
  177. data/lib/generators/landable/component/component_generator.rb +0 -0
  178. data/lib/generators/landable/component/templates/javascripts/landable/%file_name%.less +0 -0
  179. data/lib/generators/landable/component/templates/stylesheets/landable/%file_name%.less +0 -0
  180. data/lib/generators/landable/install_generator.rb +19 -0
  181. data/lib/generators/landable/landable_generator.rb +22 -0
  182. data/lib/generators/templates/landable.rb +34 -0
  183. data/lib/landable.rb +30 -0
  184. data/lib/landable/configuration.rb +115 -0
  185. data/lib/landable/core_ext/ipaddr.rb +18 -0
  186. data/lib/landable/engine.rb +69 -0
  187. data/lib/landable/error.rb +16 -0
  188. data/lib/landable/inflections.rb +4 -0
  189. data/lib/landable/layout.rb +60 -0
  190. data/lib/landable/liquid.rb +27 -0
  191. data/lib/landable/liquid/asset_tags.rb +76 -0
  192. data/lib/landable/liquid/drops.rb +46 -0
  193. data/lib/landable/liquid/filters.rb +11 -0
  194. data/lib/landable/liquid/tags.rb +91 -0
  195. data/lib/landable/migration.rb +40 -0
  196. data/lib/landable/mime_types.rb +15 -0
  197. data/lib/landable/partial.rb +46 -0
  198. data/lib/landable/seeds.rb +36 -0
  199. data/lib/landable/traffic.rb +34 -0
  200. data/lib/landable/traffic/crawl_tracker.rb +9 -0
  201. data/lib/landable/traffic/noop_tracker.rb +8 -0
  202. data/lib/landable/traffic/ping_tracker.rb +9 -0
  203. data/lib/landable/traffic/scan_tracker.rb +9 -0
  204. data/lib/landable/traffic/scrape_tracker.rb +9 -0
  205. data/lib/landable/traffic/tracker.rb +283 -0
  206. data/lib/landable/traffic/user_tracker.rb +65 -0
  207. data/lib/landable/version.rb +10 -0
  208. data/lib/tasks/landable/cucumber.rake +67 -0
  209. data/lib/tasks/landable/data.rake +166 -0
  210. data/lib/tasks/landable/pgtap.rake +26 -0
  211. data/lib/tasks/landable/rdoc.rake +11 -0
  212. data/lib/tasks/landable/seed.rake +16 -0
  213. data/lib/tasks/landable/spec.rake +15 -0
  214. data/script/cucumber +10 -0
  215. data/spec/concerns/landable/has_assets_spec.rb +75 -0
  216. data/spec/concerns/landable/table_name_spec.rb +15 -0
  217. data/spec/concerns/landable/traffic/table_name_spec.rb +16 -0
  218. data/spec/controllers/concerns/landable/variables_concern_spec.rb +66 -0
  219. data/spec/controllers/landable/api/assets_controller_spec.rb +24 -0
  220. data/spec/controllers/landable/api/categories_controller_spec.rb +45 -0
  221. data/spec/controllers/landable/api/directories_controller_spec.rb +56 -0
  222. data/spec/controllers/landable/api/page_revisions_controller_spec.rb +29 -0
  223. data/spec/controllers/landable/api/pages_controller_spec.rb +271 -0
  224. data/spec/controllers/landable/api_controller_spec.rb +189 -0
  225. data/spec/controllers/public/preview/page_revisions_controller_spec.rb +41 -0
  226. data/spec/controllers/public/preview/pages_controller_spec.rb +36 -0
  227. data/spec/controllers/public/sitemap_controller_spec.rb +25 -0
  228. data/spec/decorators/page_decorator_spec.rb +90 -0
  229. data/spec/dummy/README.rdoc +28 -0
  230. data/spec/dummy/Rakefile +6 -0
  231. data/spec/dummy/app/assets/images/foo.jpg +0 -0
  232. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  233. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  234. data/spec/dummy/app/controllers/application_controller.rb +10 -0
  235. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  236. data/spec/dummy/app/controllers/priority_controller.rb +7 -0
  237. data/spec/dummy/app/helpers/application_helper.rb +5 -0
  238. data/spec/dummy/app/mailers/.keep +0 -0
  239. data/spec/dummy/app/models/.keep +0 -0
  240. data/spec/dummy/app/models/concerns/.keep +0 -0
  241. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  242. data/spec/dummy/app/views/layouts/priority.html.erb +18 -0
  243. data/spec/dummy/app/views/partials/_foobazz.html +1 -0
  244. data/spec/dummy/app/views/priority/show.html.erb +11 -0
  245. data/spec/dummy/bin/bundle +3 -0
  246. data/spec/dummy/bin/rails +4 -0
  247. data/spec/dummy/bin/rake +4 -0
  248. data/spec/dummy/config.ru +4 -0
  249. data/spec/dummy/config/application.rb +21 -0
  250. data/spec/dummy/config/boot.rb +5 -0
  251. data/spec/dummy/config/database.yml +60 -0
  252. data/spec/dummy/config/environment.rb +5 -0
  253. data/spec/dummy/config/environments/development.rb +29 -0
  254. data/spec/dummy/config/environments/production.rb +80 -0
  255. data/spec/dummy/config/environments/test.rb +42 -0
  256. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  257. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  258. data/spec/dummy/config/initializers/inflections.rb +16 -0
  259. data/spec/dummy/config/initializers/landable.rb +22 -0
  260. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  261. data/spec/dummy/config/initializers/secret_token.rb +12 -0
  262. data/spec/dummy/config/initializers/session_store.rb +3 -0
  263. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  264. data/spec/dummy/config/locales/en.yml +23 -0
  265. data/spec/dummy/config/routes.rb +4 -0
  266. data/spec/dummy/db/structure.sql +3736 -0
  267. data/spec/dummy/lib/assets/.keep +0 -0
  268. data/spec/dummy/log/.keep +0 -0
  269. data/spec/dummy/public/404.html +58 -0
  270. data/spec/dummy/public/422.html +58 -0
  271. data/spec/dummy/public/500.html +57 -0
  272. data/spec/dummy/public/favicon.ico +0 -0
  273. data/spec/factories/asset.rb +29 -0
  274. data/spec/factories/authors.rb +12 -0
  275. data/spec/factories/category.rb +6 -0
  276. data/spec/factories/page_revision.rb +6 -0
  277. data/spec/factories/pages.rb +33 -0
  278. data/spec/factories/template.rb +13 -0
  279. data/spec/factories/theme.rb +14 -0
  280. data/spec/fixtures/assets/cthulhu.jpg +0 -0
  281. data/spec/fixtures/assets/panda.png +0 -0
  282. data/spec/fixtures/assets/sloth.png +0 -0
  283. data/spec/fixtures/assets/small.pdf +0 -0
  284. data/spec/helpers/pages_helper_spec.rb +35 -0
  285. data/spec/lib/landable/configuration_spec.rb +20 -0
  286. data/spec/lib/landable/layout_spec.rb +25 -0
  287. data/spec/lib/landable/liquid_spec.rb +24 -0
  288. data/spec/lib/landable/migration_spec.rb +51 -0
  289. data/spec/lib/landable/partial_spec.rb +84 -0
  290. data/spec/lib/landable/tracking_spec.rb +62 -0
  291. data/spec/lib/landable/traffic_spec.rb +45 -0
  292. data/spec/models/landable/access_token_spec.rb +13 -0
  293. data/spec/models/landable/asset_spec.rb +48 -0
  294. data/spec/models/landable/directory_spec.rb +36 -0
  295. data/spec/models/landable/page/errors_spec.rb +30 -0
  296. data/spec/models/landable/page_revision_spec.rb +75 -0
  297. data/spec/models/landable/page_spec.rb +377 -0
  298. data/spec/models/landable/template_spec.rb +47 -0
  299. data/spec/models/landable/theme_spec.rb +8 -0
  300. data/spec/responders/page_render_responder_spec.rb +43 -0
  301. data/spec/routing/public_page_route_spec.rb +36 -0
  302. data/spec/services/landable/authentication_service_spec.rb +61 -0
  303. data/spec/services/landable/render_service_spec.rb +103 -0
  304. data/spec/services/landable/tidy_service_spec.rb +157 -0
  305. data/spec/spec_helper.rb +38 -0
  306. data/spec/support/behaviors.rb +107 -0
  307. data/spec/support/carrier_wave.rb +17 -0
  308. data/spec/support/categories.yml +2 -0
  309. data/spec/support/helpers.rb +22 -0
  310. metadata +795 -0
@@ -0,0 +1,18 @@
1
+ require 'ipaddr'
2
+
3
+ module Landable
4
+ module CoreExt
5
+ module IPAddr
6
+ def ==(other)
7
+ case other
8
+ when true, false then false
9
+ else super
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ class IPAddr
17
+ include Landable::CoreExt::IPAddr
18
+ end
@@ -0,0 +1,69 @@
1
+ require "rack/cors"
2
+ require "active_model_serializers"
3
+ require "carrierwave"
4
+ require "rake"
5
+
6
+ module Landable
7
+ class Engine < ::Rails::Engine
8
+ isolate_namespace Landable
9
+
10
+ config.generators do |g|
11
+ g.test_framework :rspec
12
+ g.fixture_replacement :factory_girl, :dir => 'spec/factories'
13
+ end
14
+
15
+ initializer "landable.enable_cors" do |app|
16
+ config = Landable.configuration
17
+ if config.cors.enabled?
18
+ app.middleware.insert 0, Rack::Cors do
19
+ allow do
20
+ origins config.cors.origins
21
+ resource "#{config.api_namespace}/*",
22
+ methods: [:get, :post, :put, :patch, :delete],
23
+ headers: :any,
24
+ expose: 'X-Landable-Media-Type',
25
+ credentials: false,
26
+ max_age: 15.minutes
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ initializer "landable.json_schema" do |app|
33
+ if ENV['LANDABLE_VALIDATE_JSON']
34
+ require 'rack/schema'
35
+ app.middleware.use Rack::Schema
36
+ end
37
+ end
38
+
39
+ initializer "landable.seed_required" do |app|
40
+ Landable::Seeds.seed(:required) rescue nil
41
+ end
42
+
43
+ initializer "landable.create_themes" do |app|
44
+ Theme.create_from_layouts! rescue nil
45
+ end
46
+
47
+ initializer 'landable.create_templates' do |app|
48
+ Template.create_from_partials! rescue nil
49
+ end
50
+
51
+ initializer "landable.action_controller" do
52
+ ActiveSupport.on_load :action_controller do
53
+ # includes
54
+ include Landable::Traffic
55
+ include Landable::VariablesConcern
56
+
57
+ # helpers
58
+ helper Landable::PagesHelper
59
+
60
+ # tracking
61
+ if Landable.configuration.traffic_enabled
62
+ prepend_around_action :track_with_landable!
63
+ end
64
+
65
+ # end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,16 @@
1
+ module Landable
2
+ class Error < StandardError
3
+
4
+ STATUS_CODE = 500
5
+
6
+ def initialize message = nil
7
+ message ||= "Status code: #{status_code} (Hint: rescue this in your ApplicationController)"
8
+ super
9
+ end
10
+
11
+ def status_code
12
+ self.class::STATUS_CODE
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,4 @@
1
+ # TODO: require activesupport/...
2
+ ActiveSupport::Inflector.inflections do |inflect|
3
+ inflect.irregular 'medium', 'mediums'
4
+ end
@@ -0,0 +1,60 @@
1
+ # TODO: Custom resolver for db themes: http://blog.jgarciam.net/post/21098440864/database-stored-templates-on-ruby-on-rails
2
+ # TODO: Multiple extentions with tilt
3
+ # TODO: Allow converting db-backed Theme to file-backed Theme
4
+
5
+ module Landable
6
+ class Layout
7
+ def initialize(file)
8
+ @file = file
9
+ end
10
+
11
+ def process
12
+ return if @processed
13
+
14
+ path = @file.dup
15
+ self.class.paths.each { |p| path.sub!(p, '') }
16
+
17
+ path.sub!(/^\//, '')
18
+
19
+ @path, @extension = path.split('.html.', 2)
20
+
21
+ @body = File.read(@file)
22
+
23
+ @processed = true
24
+ end
25
+
26
+ def to_theme
27
+ process unless @processed
28
+
29
+ theme = Theme.where(file: @path).first_or_initialize
30
+ theme.name ||= @path.gsub('/', ' ').titlecase
31
+ theme.extension = @extension
32
+ theme.description = description if theme.description.blank? || theme.description =~ /^Defined in/
33
+ theme.body = @body
34
+ theme.editable = false
35
+ theme.thumbnail_url ||= "http://placehold.it/300x200"
36
+
37
+ theme.save!
38
+
39
+ theme
40
+ end
41
+
42
+ def description
43
+ "Defined in #@path.html.#@extension"
44
+ end
45
+
46
+ class << self
47
+ def all
48
+ files.map { |file| new(file) }
49
+ end
50
+
51
+ def files
52
+ paths.map { |path| Dir[path + "/**/[^_]*.html.*"] }.flatten
53
+ end
54
+
55
+ def paths
56
+ @paths ||= Dir[Rails.root.join('app/views/layouts').to_s]
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,27 @@
1
+ require 'liquid'
2
+
3
+ require 'landable/liquid/tags'
4
+ require 'landable/liquid/asset_tags'
5
+ require 'landable/liquid/filters'
6
+ require 'landable/liquid/drops'
7
+
8
+ # Tag generators
9
+ Liquid::Template.register_tag('title_tag', Landable::Liquid::TitleTag)
10
+ Liquid::Template.register_tag('meta_tags', Landable::Liquid::MetaTag)
11
+ Liquid::Template.register_tag('head_content', Landable::Liquid::HeadContent)
12
+ Liquid::Template.register_tag('head', Landable::Liquid::Head)
13
+ Liquid::Template.register_tag('body', Landable::Liquid::Body)
14
+
15
+ %w(img_tag image_tag javascript_include_tag stylesheet_link_tag).each do |tag|
16
+ Liquid::Template.register_tag(tag, Landable::Liquid::AssetTag)
17
+ end
18
+
19
+ # Only called tags so we can use a function-like syntax
20
+ Liquid::Template.register_tag('asset_url', Landable::Liquid::AssetAttributeTag)
21
+ Liquid::Template.register_tag('asset_description', Landable::Liquid::AssetAttributeTag)
22
+
23
+ # Template references
24
+ Liquid::Template.register_tag('template', Landable::Liquid::TemplateTag)
25
+
26
+ # Helpers
27
+ Liquid::Template.register_filter(Landable::Liquid::DefaultFilter)
@@ -0,0 +1,76 @@
1
+ require 'action_view'
2
+
3
+ module Landable
4
+ module Liquid
5
+
6
+ class AssetTag < ::Liquid::Tag
7
+ attr_accessor :tag_name, :asset_name
8
+
9
+ # we'll be calling up to methods in here
10
+ include ActionView::Helpers::AssetTagHelper
11
+
12
+ # included for asset digest support
13
+ include Sprockets::Rails::Helper
14
+
15
+ def initialize(tag_name, param, tokens)
16
+ @tag_name = tag_name
17
+ @asset_name = param.strip
18
+ @tokens = tokens
19
+ end
20
+
21
+ def render(context)
22
+ tag_method = tag_name.to_sym
23
+ tag_method = :image_tag if tag_method == :img_tag
24
+
25
+ # if this matches an application asset, use that
26
+ if assets_environment[asset_name]
27
+ send tag_method, asset_name
28
+
29
+ # otherwise, find an asset of our own
30
+ else
31
+ asset = lookup_asset context, asset_name
32
+
33
+ options = {}
34
+ options[:alt] = asset.description if tag_method == :image_tag
35
+
36
+ send tag_method, asset.public_url, options
37
+ end
38
+ end
39
+
40
+ protected
41
+
42
+ def lookup_asset(context, name)
43
+ assets = context.registers.fetch(:assets) do
44
+ raise ArgumentError.new("`assets' value was never registered with the template")
45
+ end
46
+
47
+ assets.fetch(name) do
48
+ raise ArgumentError.new("No `#{name}' asset available in #{assets.inspect}")
49
+ end
50
+ end
51
+
52
+ # stuff for sprockets
53
+ delegate :assets_prefix, :digest_assets, to: 'ActionView::Base'
54
+
55
+ # ActionView::Base.assets_environment will be nil if the pipeline is
56
+ # disabled - use this instead
57
+ def assets_environment
58
+ Rails.application.assets
59
+ end
60
+ end
61
+
62
+ class AssetAttributeTag < AssetTag
63
+ def render(context)
64
+ asset = lookup_asset context, asset_name
65
+ attribute = tag_name.sub /^asset_/, ''
66
+
67
+ if attribute == 'url'
68
+ asset.public_url
69
+ else
70
+ asset.send attribute
71
+ end
72
+ end
73
+ end
74
+
75
+ end
76
+ end
@@ -0,0 +1,46 @@
1
+ # Drops are for lazy-loading content.
2
+ # - http://www.rubydoc.info/github/Shopify/liquid/Liquid/Drop
3
+ # - https://github.com/Shopify/liquid/blob/master/lib/liquid/drop.rb
4
+
5
+ module Landable
6
+ module Liquid
7
+
8
+ # CategoryProxy gives us these:
9
+ #
10
+ # {{ categories.size }}
11
+ #
12
+ # {% for category in categories %}
13
+ # {{ category.name }}: {{ category.pages.size }} pages
14
+ # {% endfor %}
15
+ #
16
+ # <h1>Blog posts</h1>
17
+ # <ul>
18
+ # {% for page in categories.blog.pages %}
19
+ # <li><a href="{{ page.url }}">{{ page.name }}</a></li>
20
+ # {% endfor %}
21
+ # </ul>
22
+ class CategoriesDrop < ::Liquid::Drop
23
+
24
+ def before_method method_name
25
+ category_cache[method_name] ||= ::Landable::Category.find_by_slug method_name
26
+ end
27
+
28
+ def size
29
+ @size ||= Category.count
30
+ end
31
+
32
+ def each &block
33
+ ::Landable::Category.all.each &block
34
+ end
35
+
36
+
37
+ protected
38
+
39
+ def category_cache
40
+ @category_cache ||= {}
41
+ end
42
+
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,11 @@
1
+ module Landable
2
+ module Liquid
3
+
4
+ module DefaultFilter
5
+ def default(input, default_output=nil)
6
+ input.presence ? input : default_output
7
+ end
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,91 @@
1
+ require 'action_view'
2
+
3
+ module Landable
4
+ module Liquid
5
+
6
+ class Tag < ::Liquid::Tag
7
+ include ActionView::Helpers::TagHelper
8
+
9
+ protected
10
+ def lookup_page(context)
11
+ context.registers.fetch(:page) do
12
+ raise ArgumentError.new("`page' value was never registered with the template")
13
+ end
14
+ end
15
+ end
16
+
17
+ class TitleTag < Tag
18
+ def render(context)
19
+ page = lookup_page context
20
+ content_tag(:title, page.title)
21
+ end
22
+ end
23
+
24
+ class MetaTag < Tag
25
+ def render(context)
26
+ page = lookup_page context
27
+ tags = page.meta_tags || {}
28
+
29
+ tags.map { |name, value|
30
+ tag(:meta, name: name, content: value)
31
+ }.join("\n")
32
+ end
33
+ end
34
+
35
+ class HeadContent < Tag
36
+ def render(context)
37
+ page = lookup_page context
38
+
39
+ page.head_content
40
+ end
41
+ end
42
+
43
+ class Head < Tag
44
+ def render(context)
45
+ page = lookup_page context
46
+
47
+ head = []
48
+
49
+ ['title_tag', 'meta_tags', 'head_content'].each do |tag_name|
50
+ tag = eval("Landable::Liquid::#{tag_name.classify}").new(tag_name, nil, nil)
51
+ head << tag.render(context) if tag.render(context).present?
52
+ end
53
+
54
+ head.join("\n")
55
+ end
56
+ end
57
+
58
+ class Body < Tag
59
+ def render(context)
60
+ context.environments.first.fetch('body')
61
+ end
62
+ end
63
+
64
+ class TemplateTag < Tag
65
+ def initialize(tag, param, tokens)
66
+ param_tokens = param.split(/\s+/)
67
+ @template_slug = param_tokens.shift
68
+ @variables = Hash[param_tokens.join(' ').scan(/([\w_]+):\s+"([^"]*)"/)]
69
+ end
70
+
71
+ def render(context)
72
+ template = Landable::Template.find_by_slug @template_slug
73
+
74
+ if template
75
+ if template.partial?
76
+ if context.registers[:responder].present?
77
+ context.registers[:responder].controller.render_to_string(partial: template.file)
78
+ else
79
+ "<!-- render error: unable to render \"#{@template_slug}\", no controller/responder present -->"
80
+ end
81
+ else
82
+ ::Liquid::Template.parse(template.body).render @variables
83
+ end
84
+ else
85
+ "<!-- render error: missing template \"#{@template_slug}\" -->"
86
+ end
87
+ end
88
+ end
89
+
90
+ end
91
+ end
@@ -0,0 +1,40 @@
1
+ class Landable::Migration < ActiveRecord::Migration
2
+ class << self
3
+ def connection_search_path(conn)
4
+ conn.execute("SHOW SEARCH_PATH")[0]["search_path"]
5
+ end
6
+
7
+ def models
8
+ @models ||= begin
9
+ c = Landable.constants.map { |c| "Landable::#{c.to_s}".constantize }
10
+ c += Landable::Traffic.constants.map { |c| "Landable::Traffic::#{c.to_s}".constantize }
11
+ c.select { |c| c.kind_of? Class and c.ancestors.include? ActiveRecord::Base }
12
+ end
13
+ end
14
+
15
+ def clear_cache!
16
+ models.each &:reset_primary_key
17
+ ActiveRecord::Base.connection.schema_cache.clear!
18
+ end
19
+ end
20
+
21
+ def exec_migration(conn, direction)
22
+ # come what may, keep the connection's schema search path intact
23
+ with_clean_connection(conn) do
24
+ super
25
+ end
26
+
27
+ # reset a few things, lest we pollute the way for those who follow
28
+ self.class.clear_cache!
29
+ end
30
+
31
+
32
+ protected
33
+
34
+ def with_clean_connection(conn)
35
+ original_search_path = self.class.connection_search_path conn
36
+ yield
37
+ conn.schema_search_path = original_search_path
38
+ end
39
+
40
+ end