mango 0.5.4 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. data/.gitignore +1 -2
  2. data/.rvmrc +1 -0
  3. data/.yardopts +1 -3
  4. data/{CHANGES.mdown → CHANGES.md} +40 -0
  5. data/Gemfile.lock +35 -23
  6. data/LICENSE +1 -1
  7. data/{README.mdown → README.md} +38 -27
  8. data/Rakefile +0 -13
  9. data/lib/mango.rb +5 -0
  10. data/lib/mango/application.rb +361 -129
  11. data/lib/mango/content_page.rb +89 -115
  12. data/lib/mango/core_ext/string.rb +16 -0
  13. data/lib/mango/core_ext/uri.rb +14 -0
  14. data/lib/mango/dependencies.rb +5 -4
  15. data/lib/mango/flavored_markdown.rb +7 -0
  16. data/lib/mango/rack/debugger.rb +20 -0
  17. data/lib/mango/runner.rb +33 -50
  18. data/lib/mango/templates/.gitignore +0 -1
  19. data/lib/mango/templates/Gemfile +1 -1
  20. data/lib/mango/templates/content/index.erb +6 -0
  21. data/lib/mango/templates/themes/default/javascripts/timer.coffee +6 -0
  22. data/lib/mango/templates/themes/default/public/javascripts/fireworks.js +0 -0
  23. data/lib/mango/templates/themes/default/public/{styles → stylesheets}/fireworks.css +0 -0
  24. data/lib/mango/templates/themes/default/public/{styles → stylesheets}/reset.css +0 -2
  25. data/lib/mango/templates/themes/default/{styles → stylesheets}/screen.sass +0 -2
  26. data/lib/mango/templates/themes/default/views/layout.haml +5 -5
  27. data/lib/mango/templates/themes/default/views/page.haml +1 -3
  28. data/lib/mango/version.rb +1 -1
  29. data/mango.gemspec +12 -10
  30. data/spec/fixture/content/engines/erb.erb +7 -0
  31. data/spec/fixture/content/engines/haml.haml +4 -4
  32. data/spec/fixture/content/engines/liquid.liquid +7 -0
  33. data/spec/fixture/content/engines/markdown.markdown +0 -6
  34. data/spec/fixture/content/engines/md.md +0 -6
  35. data/spec/fixture/content/engines/mkd.mkd +1 -0
  36. data/spec/fixture/content/page_with_missing_view.haml +2 -2
  37. data/spec/fixture/content/page_with_unregistered_view.haml +4 -0
  38. data/spec/fixture/content/view_engines/erb.haml +4 -0
  39. data/spec/fixture/content/view_engines/liquid.haml +4 -0
  40. data/spec/fixture/themes/default/javascripts/override.coffee +1 -0
  41. data/spec/fixture/themes/default/javascripts/siblings.coffee +7 -0
  42. data/spec/fixture/themes/default/javascripts/songs/happy.coffee +5 -0
  43. data/spec/fixture/themes/default/public/404.html +11 -0
  44. data/spec/fixture/themes/default/public/javascripts/econ.js +8 -0
  45. data/spec/fixture/themes/default/public/javascripts/math/opposite.js +6 -0
  46. data/spec/fixture/themes/default/public/javascripts/override.js +1 -0
  47. data/spec/fixture/themes/default/public/root.js +5 -0
  48. data/spec/fixture/themes/default/public/{styles → stylesheets}/override.css +0 -0
  49. data/spec/fixture/themes/default/public/{styles → stylesheets}/reset.css +0 -0
  50. data/spec/fixture/themes/default/public/{styles → stylesheets}/subfolder/another.css +0 -0
  51. data/spec/fixture/themes/default/security_hole.js +1 -0
  52. data/spec/fixture/themes/default/{styles → stylesheets}/override.sass +0 -0
  53. data/spec/fixture/themes/default/{styles/screen.sass → stylesheets/sass.sass} +4 -2
  54. data/spec/fixture/themes/default/stylesheets/scss.scss +19 -0
  55. data/spec/fixture/themes/default/{styles → stylesheets}/subfolder/screen.sass +0 -2
  56. data/spec/fixture/themes/default/views/404.erb +11 -0
  57. data/spec/fixture/themes/default/views/404.haml +1 -0
  58. data/spec/fixture/themes/default/views/404.liquid +11 -0
  59. data/spec/fixture/themes/default/views/layout.erb +10 -0
  60. data/spec/fixture/themes/default/views/layout.haml +1 -1
  61. data/spec/fixture/themes/default/views/layout.liquid +10 -0
  62. data/spec/fixture/themes/default/views/page.erb +7 -0
  63. data/spec/fixture/themes/default/views/page.haml +3 -1
  64. data/spec/fixture/themes/default/views/page.liquid +7 -0
  65. data/spec/lib/application/routing_content_pages_spec.rb +298 -21
  66. data/spec/lib/application/routing_javascript_templates_spec.rb +278 -0
  67. data/spec/lib/application/routing_not_found_spec.rb +254 -0
  68. data/spec/lib/application/routing_public_files_spec.rb +9 -8
  69. data/spec/lib/application/{routing_style_sheets_spec.rb → routing_stylesheet_templates_spec.rb} +61 -24
  70. data/spec/lib/application_spec.rb +31 -2
  71. data/spec/lib/content_page/initializing_spec.rb +399 -126
  72. data/spec/lib/content_page_spec.rb +23 -19
  73. data/spec/lib/core_ext/string_spec.rb +12 -0
  74. data/spec/lib/core_ext/uri_spec.rb +42 -0
  75. data/spec/lib/dependencies_spec.rb +0 -1
  76. data/spec/lib/flavored_markdown_spec.rb +18 -3
  77. data/spec/lib/runner_spec.rb +40 -39
  78. data/spec/lib/version_spec.rb +4 -4
  79. metadata +145 -64
  80. data/lib/mango/templates/content/index.md +0 -5
  81. data/lib/mango/templates/themes/default/public/javascripts/timer.js +0 -5
  82. data/spec/fixture/content/engines/mdown.mdown +0 -7
  83. data/spec/lib/content_page/finding_spec.rb +0 -213
data/.gitignore CHANGED
@@ -1,7 +1,6 @@
1
1
  .DS_Store
2
2
  .bundle
3
- .rvmrc
3
+ .sass-cache
4
4
  .yardoc
5
5
  *.gem
6
6
  *.tmproj
7
- yardoc
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm ruby-1.9.2-p180@mango
data/.yardopts CHANGED
@@ -1,6 +1,4 @@
1
- --output-dir ./yardoc
2
1
  --markup markdown
3
- --plugin yard-sinatra
4
2
  -
5
3
  LICENSE
6
- CHANGES.mdown
4
+ CHANGES.md
@@ -1,5 +1,45 @@
1
1
  # CHANGES
2
2
 
3
+ ## v0.6.0 / 2011-05-29
4
+
5
+ [Full changes](https://github.com/ryansobol/mango/compare/v0.5.4...v0.6.0)
6
+
7
+ ## Features
8
+
9
+ * Add ERB view template support [GH#21](https://github.com/ryansobol/mango/issues/21)
10
+ * Add ERB 404 template support [GH#26](https://github.com/ryansobol/mango/issues/26)
11
+ * Add 404 default response [GH#27](https://github.com/ryansobol/mango/issues/27)
12
+ * Add 404.html public file support [GH#28](https://github.com/ryansobol/mango/issues/28)
13
+ * Add Scss stylesheet template support [GH#31](https://github.com/ryansobol/mango/issues/31)
14
+ * Add ERB content page support [GH#33](https://github.com/ryansobol/mango/issues/33)
15
+ * Use ContentPage as local `page` variable within content page and view templates [GH#34](https://github.com/ryansobol/mango/issues/34)
16
+ * Add Liquid content page, view template, and 404 template support [GH#40](https://github.com/ryansobol/mango/issues/40)
17
+ * Add CoffeeScript support and JavaScript route handler [GH#36](https://github.com/ryansobol/mango/issues/36)
18
+
19
+ ### Dependencies
20
+
21
+ * Update Sinatra to ~> 1.2.6 [GH#14](https://github.com/ryansobol/mango/issues/14)
22
+ * Update RSpec to ~> 2.6.0 [GH#32](https://github.com/ryansobol/mango/issues/32)
23
+ * Add Sass ~> 3.1.1 [GH#24](https://github.com/ryansobol/mango/issues/24)
24
+ * Update Haml to ~> 3.1.1 [GH#23](https://github.com/ryansobol/mango/issues/23)
25
+ * Update Rack::Test to ~> 0.6.0 [GH#25](https://github.com/ryansobol/mango/issues/25)
26
+ * Update YARD to ~> 0.7.1 [GH#38](https://github.com/ryansobol/mango/issues/38)
27
+
28
+ ### Chores
29
+
30
+ * Unignore .rvmrc [GH#16](https://github.com/ryansobol/mango/issues/16)
31
+ * Move `Mango::Application#directory_path?` to `URI.directory?` [GH#29](https://github.com/ryansobol/mango/issues/29)
32
+ * Move `File.templatize` to `String#templatize` and simplify usage [GH#30](https://github.com/ryansobol/mango/issues/30)
33
+ * Rename all `.mdown` files to `.md` [GH#37](https://github.com/ryansobol/mango/issues/37)
34
+ * Remove the `yard` task from the Rakefile [GH#6](https://github.com/ryansobol/mango/issues/6)
35
+ * Add spec coverage for 404.liquid route handling [GH#42](https://github.com/ryansobol/mango/issues/42)
36
+ * Update rspec-core to 2.6.2 [GH#41](https://github.com/ryansobol/mango/issues/41)
37
+ * Update tilt to 1.3.1 [GH#43](https://github.com/ryansobol/mango/issues/43)
38
+ * Update LICENSE copyright to 2011 [GH#47](https://github.com/ryansobol/mango/issues/47)
39
+ * Update rspec-core to 2.6.3 [GH#46](https://github.com/ryansobol/mango/issues/46)
40
+ * Update Tilt to 1.3.2 [GH#45](https://github.com/ryansobol/mango/issues/45)
41
+ * Update multi_json to 1.0.3 [GH#53](https://github.com/ryansobol/mango/issues/53)
42
+
3
43
  ## v0.5.4 / 2011-04-24
4
44
 
5
45
  [Full changes](https://github.com/ryansobol/mango/compare/v0.5.3...v0.5.4)
@@ -1,39 +1,49 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- mango (0.5.4)
4
+ mango (0.6.0)
5
5
  bluecloth (~> 2.1.0)
6
6
  bundler (~> 1.0.7)
7
- haml (~> 3.0.25)
7
+ coffee-script (~> 2.2.0)
8
+ haml (~> 3.1.1)
9
+ liquid (~> 2.2.2)
8
10
  rack (~> 1.2.2)
9
- sinatra (~> 1.1.4)
11
+ sass (~> 3.1.1)
12
+ sinatra (~> 1.2.6)
10
13
  thor (~> 0.14.6)
11
14
 
12
15
  GEM
13
16
  remote: http://rubygems.org/
14
17
  specs:
15
18
  bluecloth (2.1.0)
19
+ coffee-script (2.2.0)
20
+ coffee-script-source
21
+ execjs
22
+ coffee-script-source (1.1.1)
16
23
  diff-lcs (1.1.2)
17
- haml (3.0.25)
24
+ execjs (1.0.0)
25
+ multi_json (~> 1.0)
26
+ haml (3.1.1)
27
+ liquid (2.2.2)
28
+ multi_json (1.0.3)
18
29
  rack (1.2.2)
19
- rack-test (0.5.7)
30
+ rack-test (0.6.0)
20
31
  rack (>= 1.0)
21
- rspec (2.5.0)
22
- rspec-core (~> 2.5.0)
23
- rspec-expectations (~> 2.5.0)
24
- rspec-mocks (~> 2.5.0)
25
- rspec-core (2.5.1)
26
- rspec-expectations (2.5.0)
32
+ rspec (2.6.0)
33
+ rspec-core (~> 2.6.0)
34
+ rspec-expectations (~> 2.6.0)
35
+ rspec-mocks (~> 2.6.0)
36
+ rspec-core (2.6.3)
37
+ rspec-expectations (2.6.0)
27
38
  diff-lcs (~> 1.1.2)
28
- rspec-mocks (2.5.0)
29
- sinatra (1.1.4)
39
+ rspec-mocks (2.6.0)
40
+ sass (3.1.1)
41
+ sinatra (1.2.6)
30
42
  rack (~> 1.1)
31
43
  tilt (>= 1.2.2, < 2.0)
32
44
  thor (0.14.6)
33
- tilt (1.2.2)
34
- yard (0.6.8)
35
- yard-sinatra (0.5.1)
36
- yard (~> 0.6.0)
45
+ tilt (1.3.2)
46
+ yard (0.7.1)
37
47
 
38
48
  PLATFORMS
39
49
  ruby
@@ -41,12 +51,14 @@ PLATFORMS
41
51
  DEPENDENCIES
42
52
  bluecloth (~> 2.1.0)
43
53
  bundler (~> 1.0.7)
44
- haml (~> 3.0.25)
54
+ coffee-script (~> 2.2.0)
55
+ haml (~> 3.1.1)
56
+ liquid (~> 2.2.2)
45
57
  mango!
46
58
  rack (~> 1.2.2)
47
- rack-test (~> 0.5.7)
48
- rspec (~> 2.5.0)
49
- sinatra (~> 1.1.4)
59
+ rack-test (~> 0.6.0)
60
+ rspec (~> 2.6.0)
61
+ sass (~> 3.1.1)
62
+ sinatra (~> 1.2.6)
50
63
  thor (~> 0.14.6)
51
- yard (~> 0.6.8)
52
- yard-sinatra (~> 0.5.1)
64
+ yard (~> 0.7.1)
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2010 Ryan Sobol
1
+ Copyright (c) 2011 Ryan Sobol
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -1,5 +1,5 @@
1
- Mango release 0.5.4 (April 24, 2011)
2
- ====================================
1
+ Mango release 0.6.0 (May 29, 2011)
2
+ ==================================
3
3
 
4
4
  Copyright (c) 2010 Ryan Sobol. Licensed under the MIT license. Please see the {file:LICENSE} for more information.
5
5
 
@@ -27,17 +27,26 @@ Mango integrates with the writing tools you're already familiar with -- the file
27
27
 
28
28
  Working with a text editor you already know *saves time*. And writing and revising content in a file *is often easier* then using the clunky administrator interface of a CMS (e.g. WordPress). Plus, files *match perfectly* with version control systems, like [Git](http://git-scm.com/), for powerful revision history. Bonus!
29
29
 
30
+ Mango supports the following *easy to write* content formats:
31
+
32
+ * [Markdown](http://daringfireball.net/projects/markdown/basics)
33
+ * [Haml](http://haml-lang.com/tutorial.html)
34
+ * [ERB](http://ruby-doc.org/stdlib/libdoc/erb/rdoc/classes/ERB.html)
35
+ * [Liquid](https://github.com/tobi/liquid/wiki)
36
+
37
+ Don't see your favorite content format? [Patches are welcomed](https://github.com/ryansobol/mango/issues)
38
+
30
39
  ### Easy to theme
31
40
 
32
- Mango separates a website's theme from it's content. This makes it *easy to change* the look-and-feel of a single page or an entire website. Mango also supports powerful template languages that make it *easy to have uniformity* with major sections (i.e. headers, footers, navigation, sidebars, etc.) across multiple pages. The following web and template formats are supported by Mango:
41
+ Mango separates a website's theme from it's content. This makes it *easy to change* the look-and-feel of a single page or an entire website. Mango also supports powerful template languages that make it *easy to have uniformity* with major sections (i.e. headers, footers, navigation, sidebars, etc.) across multiple pages. In addition to the standard browser formats -- HTML, CSS, and JavaScript -- Mango also supports the following template engines:
33
42
 
34
- * HAML
35
- * HTML
36
- * SASS
37
- * CSS
38
- * JavaScript
43
+ * [Haml](http://haml-lang.com/)
44
+ * [ERB](http://ruby-doc.org/stdlib/libdoc/erb/rdoc/classes/ERB.html)
45
+ * [Liquid](https://github.com/tobi/liquid/wiki)
46
+ * [Scss](http://sass-lang.com/) and [Sass](http://sass-lang.com/)
47
+ * [CoffeeScript](http://jashkenas.github.com/coffee-script/)
39
48
 
40
- with [more](https://github.com/sinatra/sinatra/blob/1.1.0/CHANGES#L12) on the way.
49
+ Don't see your favorite template engine? [Patches are welcomed](https://github.com/ryansobol/mango/issues)
41
50
 
42
51
  ### Easy to publish
43
52
 
@@ -53,7 +62,7 @@ With a strong separation of writing, theming and publishing, Mango applications
53
62
 
54
63
  ### Easy to maintain
55
64
 
56
- Mango is a database-less web framework. With no database to install, configure, or manage, the maintenance needed to keep your website in working order is *drastically reduced*. And because Mango is distributed as a RubyGem and respects [Semantic Versioning](http://semver.org/), *upgrading is painless andi backwards-compatible* between patch releases.
65
+ Mango is a database-less web framework. With no database to install, configure, or manage, the maintenance needed to keep your website in working order is *drastically reduced*. And because Mango is distributed as a RubyGem and respects [Semantic Versioning](http://semver.org/), *upgrading is painless and backwards-compatible* between patch releases.
57
66
 
58
67
  ### Easy to scale
59
68
 
@@ -74,18 +83,20 @@ REQUIREMENTS
74
83
  * [RubyGems](https://rubygems.org/) >= 1.3.7 (bundled with Ruby)
75
84
  * [Bundler](http://gembundler.com/) ~> 1.0.7
76
85
  * [Rack](http://rack.rubyforge.org/) ~> 1.2.2
77
- * [Sinatra](http://www.sinatrarb.com/) ~> 1.1.4
78
- * [Haml](http://haml-lang.com/) ~> 3.0.25
79
- * [Sass](http://sass-lang.com/) ~> 3.0.25 (bundled with Haml)
86
+ * [Sinatra](http://www.sinatrarb.com/) ~> 1.2.6
87
+ * [Haml](http://haml-lang.com/) ~> 3.1.1
88
+ * [Sass](http://sass-lang.com/) ~> 3.1.1
80
89
  * [BlueCloth](http://deveiate.org/projects/BlueCloth) ~> 2.1.0
90
+ * [Liquid](http://www.liquidmarkup.org/) ~> 2.2.2
91
+ * [CoffeeScript](http://jashkenas.github.com/coffee-script/) ~> 2.2.0
81
92
  * [Thor](https://github.com/wycats/thor) ~> 0.14.6
82
93
 
83
94
  ### Optional development dependencies
84
95
 
85
96
  * [Rake](http://rake.rubyforge.org/) ~> 0.8.7 (bundled with Ruby)
86
- * [Rack::Test](https://github.com/brynary/rack-test) ~> 0.5.7
87
- * [RSpec](http://rspec.info/) ~> 2.5.0
88
- * [YARD](http://yardoc.org/) ~> 0.6.8
97
+ * [Rack::Test](https://github.com/brynary/rack-test) ~> 0.6.0
98
+ * [RSpec](http://rspec.info/) ~> 2.6.0
99
+ * [YARD](http://yardoc.org/) ~> 0.7.1
89
100
  * [YARD::Sinatra](https://github.com/rkh/yard-sinatra) ~> 0.5.1
90
101
  * [BlueCloth](http://deveiate.org/projects/BlueCloth) ~> 2.1.0
91
102
 
@@ -117,7 +128,7 @@ Simply edit the gem version in your application's `Gemfile` and re-install with
117
128
  $ cat Gemfile
118
129
  # encoding: UTF-8
119
130
  source "http://rubygems.org"
120
- gem "mango", "~> 0.5.4"
131
+ gem "mango", "~> 0.6.0"
121
132
  $ bundle install
122
133
 
123
134
  **TIP:** If you're working in the insolation of an [RVM gemset](http://rvm.beginrescueend.com/gemsets/basics/), type `gem clean` to uninstall outdated gems.
@@ -166,21 +177,22 @@ Now that the newly generated Mango application is running, here's how the applic
166
177
  ├── README.md
167
178
  ├── config.ru
168
179
  ├── content
169
- │ └── index.md
180
+ │ └── index.erb
170
181
  └── themes
171
182
  └── default
183
+ ├── javascripts
184
+ │ └── timer.coffee
172
185
  ├── public
173
186
  │ ├── favicon.ico
174
187
  │ ├── images
175
188
  │ │ └── particles.gif
176
189
  │ ├── javascripts
177
- │ │ ├── fireworks.js
178
- │ │ └── timer.js
190
+ │ │ └── fireworks.js
179
191
  │ ├── robots.txt
180
- │ └── styles
192
+ │ └── stylesheets
181
193
  │ ├── fireworks.css
182
194
  │ └── reset.css
183
- ├── styles
195
+ ├── stylesheets
184
196
  │ └── screen.sass
185
197
  └── views
186
198
  ├── 404.haml
@@ -193,11 +205,10 @@ Now that the newly generated Mango application is running, here's how the applic
193
205
 
194
206
  * First, Mango tries to route an HTTP request to a static file found in `themes/default/public/`.
195
207
  * If no static file is found, Mango tries to route the request to a template file.
196
- * For routes ending in `.css`, Mango searches for [Sass](http://sass-lang.com/) styles found in `themes/styles/`.
197
- * For all other routes:
198
- * Mango searches for [Markdown](http://daringfireball.net/projects/markdown/syntax) or [Haml](http://haml-lang.com/) content pages in `content/`.
199
- * Mango will also try to wrap the content page within [Haml](http://haml-lang.com/) page and layout templates in `themes/default/views`.
200
- * If no static or template file is found, Mango routes unknown HTTP requests to a customizable 404 page found in `themes/default/views`.
208
+ * For routes ending in `.js`, Mango searches for a stylesheet template in `themes/javascripts/`.
209
+ * For routes ending in `.css`, Mango searches for a stylesheet template in `themes/stylesheets/`.
210
+ * For all other routes, Mango searches for a content page in `content/` and wraps it within a view template in `themes/default/views`.
211
+ * If no static or template file is found, Mango routes unknown HTTP requests to a customizable 404 page found in either `themes/default/public` or `themes/default/views`.
201
212
 
202
213
  WRITING
203
214
  -------
data/Rakefile CHANGED
@@ -15,19 +15,6 @@ end
15
15
 
16
16
  ###################################################################################################
17
17
 
18
- begin
19
- require "yard"
20
- require "bluecloth" # for Markdown support
21
- require "yard/sinatra" # for Sinatra support
22
- YARD::Rake::YardocTask.new(:yard) do |t|
23
- t.options += ["--title", "Mango #{Mango::VERSION} Documentation"]
24
- end
25
- rescue LoadError => e
26
- Mango::Dependencies.create_warning_for(e)
27
- end
28
-
29
- ###################################################################################################
30
-
31
18
  namespace :gem do
32
19
  desc "Builds a gem from the current project's Gem::Specification"
33
20
  task :build do
@@ -4,7 +4,12 @@
4
4
  require File.expand_path("mango/dependencies", File.dirname(__FILE__))
5
5
 
6
6
  require_relative "mango/version"
7
+ require_relative "mango/core_ext/string"
8
+ require_relative "mango/core_ext/uri"
7
9
  require_relative "mango/rack/debugger"
8
10
  require_relative "mango/application"
9
11
  require_relative "mango/flavored_markdown"
10
12
  require_relative "mango/content_page"
13
+
14
+ # @see http://en.wikipedia.org/wiki/Mango
15
+ module Mango; end
@@ -2,6 +2,10 @@
2
2
  require "sinatra/base"
3
3
  require "haml"
4
4
  require "sass"
5
+ require "erb"
6
+ require "liquid"
7
+ require "bluecloth"
8
+ require "coffee_script"
5
9
 
6
10
  module Mango
7
11
  # It's probably no surprise that `Mango::Application` is a modular **application controller**
@@ -12,10 +16,11 @@ module Mango
12
16
  # For **every HTTP request**, the application will first attempt to match the request URI path to
13
17
  # a public file found within `settings.public` and send that file with a 200 response code.
14
18
  #
15
- # In addition to serving static assets, the application has two dynamic route handlers:
19
+ # In addition to serving static assets, the application has these dynamic route handlers:
16
20
  #
17
21
  # * Content page templates with `GET *`
18
- # * Style sheet templates with `GET /styles/*.css`
22
+ # * JavaScript templates with `GET /javascripts/*.js`
23
+ # * Stylesheet templates with `GET /stylesheets/*.css`
19
24
  #
20
25
  # and one error handler:
21
26
  #
@@ -23,7 +28,7 @@ module Mango
23
28
  #
24
29
  # # Serving public files found within `settings.public`
25
30
  #
26
- # ### Example requests routed to public files (with potential security holes)
31
+ # ### Example requests routed to public files
27
32
  #
28
33
  # |-- content
29
34
  # | `-- override.haml
@@ -47,86 +52,199 @@ module Mango
47
52
  #
48
53
  # # Content page templates with `GET *`
49
54
  #
50
- # ### Example `GET *` requests routed to content pages (with potential security holes)
55
+ # ### Example `GET *` requests routed to content page templates
51
56
  #
52
57
  # |-- content
53
58
  # | |-- about
54
- # | | |-- index.haml
59
+ # | | |-- index.erb
55
60
  # | | `-- us.haml
56
- # | |-- index.haml
61
+ # | |-- index.markdown
57
62
  # | |-- override.haml
58
63
  # | `-- turner+hooch.haml
59
64
  # `-- security_hole.haml
60
65
  #
61
- # GET / => 200 content/index.haml
62
- # GET /index => 200 content/index.haml
63
- # GET /index?foo=bar => 200 content/index.haml
64
- # GET /about/ => 200 content/about/index.haml
65
- # GET /about/index => 200 content/about/index.haml
66
+ # GET / => 200 content/index.markdown
67
+ # GET /index => 200 content/index.markdown
68
+ # GET /index?foo=bar => 200 content/index.markdown
69
+ # GET /about/ => 200 content/about/index.erb
70
+ # GET /about/index => 200 content/about/index.erb
66
71
  # GET /about/us => 200 content/about/us.haml
67
72
  # GET /turner%2Bhooch => 200 content/turner+hooch.haml
68
73
  #
69
74
  # GET /page_not_found => pass to NOT_FOUND error handler
70
75
  # GET /../security_hole => pass to NOT_FOUND error handler
71
76
  #
72
- # # Style sheet templates with `GET /styles/*.css`
77
+ # # JavaScript templates with `GET /javascripts/*.js`
73
78
  #
74
- # ### Example `GET /styles/*.css` requests routed to style sheets (with potential security holes)
79
+ # ### Example `GET /javascripts/*.js` requests routed to JavaScript files and templates
80
+ #
81
+ # `-- themes
82
+ # `-- default
83
+ # |-- javascripts
84
+ # | |-- override.coffee
85
+ # | |-- siblings.coffee
86
+ # | `-- songs
87
+ # | `-- happy.coffee
88
+ # |-- public
89
+ # | |-- root.js
90
+ # | `-- stylesheets
91
+ # | |-- econ.js
92
+ # | |-- math
93
+ # | | `-- opposite.js
94
+ # | `-- override.js
95
+ # `-- security_hole.js
96
+ #
97
+ # GET /javascripts/siblings.js => 200 themes/default/stylesheets/siblings.coffee
98
+ # GET /javascripts/songs/happy.js => 200 themes/default/stylesheets/songs/happy.coffee
99
+ #
100
+ # GET /javascripts/econ.js => 200 themes/default/public/javascripts/econ.js
101
+ # GET /javascripts/override.js => 200 themes/default/public/javascripts/override.js
102
+ # GET /root.js => 200 themes/default/public/root.js
103
+ # GET /javascripts/math/opposite.js => 200 themes/default/public/javascripts/math/opposite.js
104
+ #
105
+ # GET /javascripts/not_found.js => pass to NOT_FOUND error handler
106
+ # GET /siblings.js => pass to NOT_FOUND error handler
107
+ # GET /javascripts/../security_hole.js => pass to NOT_FOUND error handler
108
+ #
109
+ # # Stylesheet templates with `GET /stylesheets/*.css`
110
+ #
111
+ # ### Example `GET /stylesheets/*.css` requests routed to stylesheets files and templates
75
112
  #
76
113
  # `-- themes
77
114
  # `-- default
78
115
  # |-- public
79
116
  # | |-- default.css
80
- # | `-- styles
117
+ # | `-- stylesheets
81
118
  # | |-- override.css
82
119
  # | |-- reset.css
83
- # | `-- subfolder
84
- # | `-- another.css
120
+ # | `-- folder
121
+ # | `-- print.css
85
122
  # |-- security_hole.sass
86
- # `-- styles
123
+ # `-- stylesheets
87
124
  # |-- override.sass
88
- # |-- screen.sass
89
- # `-- subfolder
90
- # `-- screen.sass
125
+ # |-- screen.scss
126
+ # `-- folder
127
+ # `-- mobile.sass
91
128
  #
92
- # GET /styles/screen.css => 200 themes/default/styles/screen.sass
93
- # GET /styles/subfolder/screen.css => 200 themes/default/styles/subfolder/screen.sass
129
+ # GET /stylesheets/screen.css => 200 themes/default/stylesheets/screen.scss
130
+ # GET /stylesheets/folder/mobile.css => 200 themes/default/stylesheets/folder/mobile.sass
94
131
  #
95
- # GET /styles/reset.css => 200 themes/default/public/styles/reset.css
96
- # GET /styles/override.css => 200 themes/default/public/styles/override.css
132
+ # GET /stylesheets/reset.css => 200 themes/default/public/stylesheets/reset.css
133
+ # GET /stylesheets/override.css => 200 themes/default/public/stylesheets/override.css
97
134
  # GET /default.css => 200 themes/default/public/default.css
98
- # GET /styles/subfolder/another.css => 200 themes/default/public/styles/subfolder/another.css
135
+ # GET /stylesheets/folder/print.css => 200 themes/default/public/stylesheets/folder/print.css
99
136
  #
100
- # GET /styles/style_not_found.css => pass to NOT_FOUND error handler
101
- # GET /screen.css => pass to NOT_FOUND error handler
102
- # GET /styles/../security_hole.css => pass to NOT_FOUND error handler
137
+ # GET /stylesheets/not_found.css => pass to NOT_FOUND error handler
138
+ # GET /screen.css => pass to NOT_FOUND error handler
139
+ # GET /stylesheets/../security_hole.css => pass to NOT_FOUND error handler
103
140
  #
104
141
  # # 404 Page Not Found with `NOT_FOUND`
105
142
  #
106
143
  # When a requested URI path cannot be matched with a public file or template file, the error
107
- # handler renders the 404 template and sends it with a 404 response.
144
+ # handler attempts to send a 404 public file or a rendered a 404 template with a 404 HTTP
145
+ # response.
146
+ #
147
+ # ### Example `GET /page_not_found` request routed to a 404 public file
148
+ #
149
+ # `-- themes
150
+ # `-- default
151
+ # `-- public
152
+ # `-- 404.html
153
+ #
154
+ # GET /page_not_found => 404 themes/default/public/404.html
155
+ #
156
+ # ### Example `GET /page_not_found` request routed to a 404 Haml template
157
+ #
158
+ # |-- content
159
+ # | `-- index.haml
160
+ # `-- themes
161
+ # `-- default
162
+ # `-- views
163
+ # `-- 404.haml
164
+ #
165
+ # GET /page_not_found => 404 themes/default/views/404.haml
166
+ #
167
+ # If no 404 public file or template is found, the application sends a basic "Page Not Found" page
168
+ # with a 404 HTTP response.
108
169
  #
109
170
  class Application < Sinatra::Base
110
- set :root, Dir.getwd
111
- set :theme, "default"
112
- set :views, lambda { File.join(root, "themes", theme, "views") }
113
- set :public, lambda { File.join(root, "themes", theme, "public") }
114
- set :styles, lambda { File.join(root, "themes", theme, "styles") }
115
- set :content, lambda { File.join(root, "content") }
171
+ # @macro [attach] sinatra.set
172
+ # Defines `settings.$1`
173
+ # @attribute
174
+ # @overload $*
175
+ # @return [String]
176
+ set :root, Dir.getwd
177
+ set :theme, "default"
178
+ set :javascripts, lambda { File.join(root, "themes", theme, "javascripts") }
179
+ set :public, lambda { File.join(root, "themes", theme, "public") }
180
+ set :stylesheets, lambda { File.join(root, "themes", theme, "stylesheets") }
181
+ set :views, lambda { File.join(root, "themes", theme, "views") }
182
+ set :content, lambda { File.join(root, "content") }
183
+
184
+ # @macro [attach] sinatra.mime_type
185
+ # Registers `$2` as the mime type for static files ending with `$1`
186
+ # @scope class
187
+ # @attribute
188
+ # @overload $*
189
+ # @return [String]
190
+ mime_type "", "text/html"
116
191
 
192
+ # @macro [attach] sinatra.configure
193
+ # Run once, at startup, when the environment is set to `${1--1}`
194
+ # @scope class
195
+ # @attribute
196
+ # @overload configure ${1--1}
117
197
  configure :development do
118
198
  use Mango::Rack::Debugger
119
199
  end
120
200
 
121
- # For static files that don't have an extension, send the file as HTML content
122
- #
123
- mime_type "", "text/html"
201
+ # Supported JavaScript template engines
202
+ JAVASCRIPT_TEMPLATE_ENGINES = {
203
+ Tilt::CoffeeScriptTemplate => :coffee
204
+ }
205
+
206
+ # Supported stylesheet template engines
207
+ STYLESHEET_TEMPLATE_ENGINES = {
208
+ Tilt::ScssTemplate => :scss,
209
+ Tilt::SassTemplate => :sass
210
+ }
211
+
212
+ # Supported view template engines
213
+ VIEW_TEMPLATE_ENGINES = {
214
+ Tilt::HamlTemplate => :haml,
215
+ Tilt::ERBTemplate => :erb,
216
+ Tilt::LiquidTemplate => :liquid
217
+ }
218
+
219
+ ###############################################################################################
220
+
221
+ private
124
222
 
125
- # Renders the `404.haml` template found within `settings.views` and sends it with 404 HTTP
126
- # response.
223
+ # Renders a 404 page with a 404 HTTP response code.
127
224
  #
128
- # The `404.haml` template is **not** wrapped within the `layout.haml` template when rendered,
129
- # even if one exists within `settings.views`.
225
+ # First, the application attempts to render a public 404 file stored in `settings.public`. If
226
+ # a public 404 file is found, the application will:
227
+ #
228
+ # * Send the public 404 file with a 404 HTTP response code
229
+ # * Halt execution
230
+ #
231
+ # For example:
232
+ #
233
+ # `-- themes
234
+ # `-- default
235
+ # `-- public
236
+ # `-- 404.html
237
+ #
238
+ # GET /page_not_found => 404 themes/default/public/404.html
239
+ #
240
+ # If no match is found, the application attempts to render a 404 template stored in
241
+ # `settings.views`. If a 404 template is found, the application *will not* render it within a
242
+ # layout template, even if an appropriately named layout template exists within
243
+ # `settings.views`. If a 404 template is found, the application will:
244
+ #
245
+ # * Render the 404 template, without a layout template, as HTML
246
+ # * Send the rendered 404 template with a 404 HTTP response code
247
+ # * Halt execution
130
248
  #
131
249
  # For example:
132
250
  #
@@ -139,16 +257,53 @@ module Mango
139
257
  #
140
258
  # GET /page_not_found => 404 themes/default/views/404.haml
141
259
  #
260
+ # Finally, if no matches are found, the application sends a basic "Page Not Found" page with a
261
+ # 404 HTTP response code.
262
+ #
263
+ # @method not_found
264
+ # @visibility public
265
+ #
142
266
  not_found do
143
- haml :"404", :layout => false
267
+ file_name = "404"
268
+ render_404_public_file! file_name
269
+ render_404_template! file_name
270
+ "<!DOCTYPE html><title>404 Page Not Found</title><h1>404 Page Not Found</h1>"
144
271
  end
145
272
 
146
- # Attempts to render style sheet templates found within `settings.styles`
273
+ # Given a file name, attempts to send an public 404 file, if it exists, and halt
147
274
  #
148
- # First, the application attempts to match the URI path with a public CSS file stored in
149
- # `settings.public`. If a public CSS file is found, the handler will:
275
+ # @param [String] file_name
150
276
  #
151
- # * Send the public CSS file with a 200 HTTP response code
277
+ def render_404_public_file!(file_name)
278
+ four_oh_four_path = File.expand_path("#{file_name}.html", settings.public)
279
+ return unless File.file?(four_oh_four_path)
280
+ send_file four_oh_four_path
281
+ end
282
+
283
+ # Given a template name, and with a prioritized list of template engines, attempts to render a
284
+ # 404 template, if one exists, and halt.
285
+ #
286
+ # @param [String] template_name
287
+ # @see VIEW_TEMPLATE_ENGINES
288
+ #
289
+ def render_404_template!(template_name)
290
+ VIEW_TEMPLATE_ENGINES.each do |engine, extension|
291
+ @preferred_extension = extension.to_s
292
+ find_template(settings.views, template_name, engine) do |file|
293
+ next unless File.file?(file)
294
+ halt send(extension, template_name.to_sym, :layout => false)
295
+ end
296
+ end
297
+ end
298
+
299
+ ###############################################################################################
300
+
301
+ # Attempts to render JavaScript templates found within `settings.javascripts`
302
+ #
303
+ # First, the application attempts to match the URI path with a public JavaScript file stored in
304
+ # `settings.public`. If a public JavaScript file is found, the application will:
305
+ #
306
+ # * Send the public JavaScript file with a 200 HTTP response code
152
307
  # * Halt execution
153
308
  #
154
309
  # For example:
@@ -156,68 +311,135 @@ module Mango
156
311
  # `-- themes
157
312
  # `-- default
158
313
  # `-- public
159
- # `-- styles
160
- # `-- reset.css
314
+ # `-- javascripts
315
+ # `-- jquery.js
161
316
  #
162
- # GET /styles/reset.css => 200 themes/default/public/styles/reset.css
317
+ # GET /javascripts/jquery.js => 200 themes/default/public/javascripts/jquery.js
163
318
  #
164
- # If no match is found, the route handler attempts to match the URI path with a style sheet
165
- # template stored in `settings.styles`. If a style sheet template is found, the handler will:
319
+ # If no match is found, the route handler attempts to match the URI path with a JavaScript
320
+ # template stored in `settings.javascripts`. If a JavaScript template is found, the
321
+ # application will:
166
322
  #
167
- # * Convert the style sheet template from Sass to CSS
168
- # * Send the converted style with a 200 HTTP response code
323
+ # * Render the template as Javascript
324
+ # * Send the rendered template with a 200 HTTP response code
169
325
  # * Halt execution
170
326
  #
171
327
  # For example:
172
328
  #
173
329
  # `-- themes
174
330
  # `-- default
175
- # `-- styles
176
- # `-- screen.sass
331
+ # `-- javascripts
332
+ # `-- bundle.coffee
177
333
  #
178
- # GET /styles/screen.css => 200 themes/default/styles/screen.sass
334
+ # GET /javascripts/bundle.js => 200 themes/default/javascripts/bundle.coffee
179
335
  #
180
- # **It's intended that requests to public CSS files and requests to style sheet templates share
181
- # the `/styles/` prefix.**
336
+ # **It's intended that requests to public JavaScript files and requests to JavaScript templates
337
+ # share the `/javascripts/` prefix.**
182
338
  #
183
339
  # Finally, if no matches are found, the route handler passes execution to the `NOT_FOUND` error
184
340
  # handler.
185
341
  #
186
- get "/styles/*.css" do |uri_path|
187
- render_style_sheet! uri_path
342
+ # @macro [attach] sinatra.get
343
+ # @overload get "$1"
344
+ # @visibility public
345
+ # @method get_js
346
+ #
347
+ get "/javascripts/*.js" do |uri_path|
348
+ render_javascript_template! uri_path
188
349
  not_found
189
350
  end
190
351
 
191
- ###############################################################################################
192
-
193
- private
194
-
195
- # Given a URI path, attempts to render a style sheet, if it exists, and halt
352
+ # Given a URI path, attempts to render a JavaScript template, if it exists, and halt
196
353
  #
197
354
  # @param [String] uri_path
355
+ # @see JAVASCRIPT_TEMPLATE_ENGINES
198
356
  #
199
- def render_style_sheet!(uri_path)
200
- styles_match = File.join(settings.styles, "*")
201
- style_sheet_path = build_style_sheet_path(uri_path)
357
+ def render_javascript_template!(uri_path)
358
+ javascript_match = File.join(settings.javascripts, "*")
359
+ javascript_path = File.expand_path(uri_path, settings.javascripts)
202
360
 
203
- return unless File.fnmatch(styles_match, style_sheet_path)
204
- return unless File.file?(style_sheet_path)
361
+ return unless File.fnmatch(javascript_match, javascript_path)
205
362
 
206
- content_type "text/css"
207
- halt sass(uri_path.to_sym, :views => settings.styles)
363
+ JAVASCRIPT_TEMPLATE_ENGINES.each do |engine, extension|
364
+ @preferred_extension = extension.to_s
365
+ find_template(settings.javascripts, uri_path, engine) do |file|
366
+ next unless File.file?(file)
367
+ halt send(extension, uri_path.to_sym, :views => settings.javascripts)
368
+ end
369
+ end
208
370
  end
209
371
 
210
- # Given a URI path, build a path to a potential style sheet
372
+ ###############################################################################################
373
+
374
+ # Attempts to render stylesheet templates found within `settings.stylesheets`
375
+ #
376
+ # First, the application attempts to match the URI path with a public stylesheet file stored in
377
+ # `settings.public`. If a public stylesheet file is found, the application will:
378
+ #
379
+ # * Send the public stylesheet file with a 200 HTTP response code
380
+ # * Halt execution
381
+ #
382
+ # For example:
383
+ #
384
+ # `-- themes
385
+ # `-- default
386
+ # `-- public
387
+ # `-- stylesheets
388
+ # `-- reset.css
389
+ #
390
+ # GET /stylesheets/reset.css => 200 themes/default/public/stylesheets/reset.css
391
+ #
392
+ # If no match is found, the route handler attempts to match the URI path with a stylesheet
393
+ # template stored in `settings.stylesheets`. If a stylesheet template is found, the
394
+ # application will:
395
+ #
396
+ # * Render the template as CSS
397
+ # * Send the rendered template with a 200 HTTP response code
398
+ # * Halt execution
399
+ #
400
+ # For example:
401
+ #
402
+ # `-- themes
403
+ # `-- default
404
+ # `-- stylesheets
405
+ # `-- screen.scss
406
+ #
407
+ # GET /stylesheets/screen.css => 200 themes/default/stylesheets/screen.scss
408
+ #
409
+ # **It's intended that requests to public stylesheet files and requests to stylesheet templates
410
+ # share the `/stylesheets/` prefix.**
411
+ #
412
+ # Finally, if no matches are found, the route handler passes execution to the `NOT_FOUND` error
413
+ # handler.
414
+ #
415
+ # @method get_css
416
+ #
417
+ get "/stylesheets/*.css" do |uri_path|
418
+ render_stylesheet_template! uri_path
419
+ not_found
420
+ end
421
+
422
+ # Given a URI path, attempts to render a stylesheet template, if it exists, and halt
211
423
  #
212
424
  # @param [String] uri_path
213
- # @param [String] format (defaults to `sass`)
214
- # @return [String] The path to a potential style sheet
425
+ # @see STYLESHEET_TEMPLATE_ENGINES
215
426
  #
216
- def build_style_sheet_path(uri_path, format = "sass")
217
- File.expand_path("#{uri_path}.#{format}", settings.styles)
427
+ def render_stylesheet_template!(uri_path)
428
+ stylesheet_match = File.join(settings.stylesheets, "*")
429
+ stylesheet_path = File.expand_path(uri_path, settings.stylesheets)
430
+
431
+ return unless File.fnmatch(stylesheet_match, stylesheet_path)
432
+
433
+ STYLESHEET_TEMPLATE_ENGINES.each do |engine, extension|
434
+ @preferred_extension = extension.to_s
435
+ find_template(settings.stylesheets, uri_path, engine) do |file|
436
+ next unless File.file?(file)
437
+ halt send(extension, uri_path.to_sym, :views => settings.stylesheets)
438
+ end
439
+ end
218
440
  end
219
441
 
220
- public
442
+ ###############################################################################################
221
443
 
222
444
  # Attempts to render content page templates found within `settings.content`
223
445
  #
@@ -237,52 +459,55 @@ module Mango
237
459
  # GET /hello_word.html => 200 themes/default/public/hello_word.html
238
460
  #
239
461
  # If no match is found, the route handler attempts to match the URI path with a content page
240
- # template stored in `settings.content`. If a content page template is found, the handler will:
462
+ # template stored in `settings.content`. If a content page template is found, the application
463
+ # will:
241
464
  #
242
- # * Read the content page into memory and assign it to the `@content_page` instance variable
465
+ # * Read the content page from disk and render the data in memory
243
466
  # * Render the content page's view template file (see `Mango::ContentPages`)
244
- # * A `RuntimeError` is raised if the view template does not exist within `settings.views`
467
+ # * An exception is raised if a registered engine for the view template file cannot be
468
+ # found or if the view template file cannot be found within `settings.views`.
245
469
  # * Send the rendered page with a 200 HTTP response code and halt execution
246
470
  #
247
- # In addition, if a `layout.haml` template exists within `settings.views`, the page's view
248
- # template is wrapped within this layout when rendered.
471
+ # In addition, if a `layout` template file exists within `settings.views` and that layout
472
+ # template file shares the same file extension as the view template, then the page's view
473
+ # template is wrapped within this layout template when rendered.
249
474
  #
250
- # For example:
475
+ # For example, given the following mango application:
251
476
  #
252
477
  # |-- content
253
- # | `-- index.haml
478
+ # | `-- index.markdown
254
479
  # `-- themes
255
480
  # `-- default
256
481
  # `-- views
257
482
  # |-- layout.haml
258
483
  # `-- page.haml
259
484
  #
260
- # GET /index => 200 content/index.haml +
485
+ # where the `index.markdown` content page's view template file is `page.haml`, then:
486
+ #
487
+ # GET /index => 200 content/index.markdown +
261
488
  # themes/default/views/page.haml +
262
489
  # themes/default/views/layout.haml
263
490
  #
264
491
  # Finally, if no matches are found, the route handler passes execution to the `NOT_FOUND` error
265
492
  # handler.
266
493
  #
494
+ # @method get_all
495
+ #
267
496
  get "/*" do |uri_path|
268
497
  render_index_file! uri_path
269
498
  render_content_page! uri_path
270
499
  not_found
271
500
  end
272
501
 
273
- ###############################################################################################
274
-
275
- private
276
-
277
502
  # Given a URI path, attempts to send an index.html file, if it exists, and halt
278
503
  #
279
504
  # @param [String] uri_path
280
505
  #
281
506
  def render_index_file!(uri_path)
282
- return unless directory_path?(uri_path)
507
+ return unless URI.directory?(uri_path)
283
508
 
284
509
  index_match = File.join(settings.public, "*")
285
- index_file_path = build_index_file_path(uri_path)
510
+ index_file_path = File.expand_path(uri_path + "index.html", settings.public)
286
511
 
287
512
  return unless File.fnmatch(index_match, index_file_path)
288
513
  return unless File.file?(index_file_path)
@@ -290,65 +515,72 @@ module Mango
290
515
  send_file index_file_path
291
516
  end
292
517
 
293
- # Given a URI path, build a path to a potential index.html file
294
- #
295
- # @param [String] uri_path
296
- # @return [String] The path to a potential index.html file
297
- #
298
- def build_index_file_path(uri_path)
299
- uri_path += "index.html"
300
- File.expand_path(uri_path, settings.public)
301
- end
518
+ # Raised when a content page is not found on disk
519
+ class ContentPageNotFound < RuntimeError; end
302
520
 
303
- ###############################################################################################
521
+ # Raised when a registered engine for the content page's view template cannot be found in
522
+ # `VIEW_TEMPLATE_ENGINES`
523
+ class RegisteredEngineNotFound < RuntimeError; end
304
524
 
305
- private
525
+ # Raised when the content page's view template cannot be found on disk
526
+ class ViewTemplateNotFound < RuntimeError; end
306
527
 
307
528
  # Given a URI path, attempts to render a content page, if it exists, and halt
308
529
  #
309
530
  # @param [String] uri_path
310
- # @raise [RuntimeError] Raised when the content page's view template cannot be found
531
+ # @raise [RegisteredEngineNotFound] Raised when a registered engine for the content page's
532
+ # view template cannot be found
533
+ # @raise [ViewTemplateNotFound] Raised when the content page's view template cannot be found
311
534
  #
312
535
  def render_content_page!(uri_path)
536
+ uri_path += "index" if URI.directory?(uri_path)
537
+
313
538
  content_match = File.join(settings.content, "*")
314
- content_page_path = build_content_page_path(uri_path)
539
+ content_page_path = File.expand_path(uri_path, settings.content)
315
540
  return unless File.fnmatch(content_match, content_page_path)
316
541
 
317
542
  begin
318
- @content_page = Mango::ContentPage.find_by_path(content_page_path)
319
- rescue Mango::ContentPage::PageNotFound
543
+ content_page = find_content_page(uri_path)
544
+ rescue ContentPageNotFound
320
545
  return
321
546
  end
322
547
 
548
+ view_template_path = File.expand_path(content_page.view, settings.views)
549
+
550
+ begin
551
+ engine = VIEW_TEMPLATE_ENGINES.fetch(Tilt[content_page.view])
552
+ rescue KeyError
553
+ message = "Cannot find registered engine for view template file -- #{view_template_path}"
554
+ raise RegisteredEngineNotFound, message
555
+ end
556
+
323
557
  begin
324
- halt haml(@content_page.view)
558
+ halt send(engine, content_page.view.to_s.templatize, :locals => { :page => content_page })
325
559
  rescue Errno::ENOENT
326
- view_path = File.expand_path("#{@content_page.view}.haml", settings.views)
327
- raise "Unable to find a view template file -- #{view_path}"
560
+ message = "Cannot find view template file -- #{view_template_path}"
561
+ raise ViewTemplateNotFound, message
328
562
  end
329
563
  end
330
564
 
331
- # Given a URI path, build a path to a potential content page
565
+ # Given a URI path, creates a new `ContentPage` instance by searching for and reading a content
566
+ # file from disk. Content files are searched consecutively until a page with a supported
567
+ # content page template engine is found.
332
568
  #
333
569
  # @param [String] uri_path
334
- # @return [String] The path to a potential content page
335
- #
336
- def build_content_page_path(uri_path)
337
- uri_path += "index" if directory_path?(uri_path)
338
- File.expand_path(uri_path, settings.content)
339
- end
340
-
341
- ###############################################################################################
342
-
343
- private
570
+ # @raise [ContentPageNotFound] Raised when a content page cannot be found for the uri path
571
+ # @return [ContentPage] A new instance is created and returned when found
572
+ # @see ContentPage::TEMPLATE_ENGINES
573
+ #
574
+ def find_content_page(uri_path)
575
+ ContentPage::TEMPLATE_ENGINES.each do |engine, extension|
576
+ @preferred_extension = extension.to_s
577
+ find_template(settings.content, uri_path, engine) do |file|
578
+ next unless File.file?(file)
579
+ return ContentPage.new(:data => File.read(file), :engine => engine)
580
+ end
581
+ end
344
582
 
345
- # Given a URI path, determine whether or no it looks like a directory path
346
- #
347
- # @param [String] uri_path
348
- # @return [Boolean] `true` if the path is empty or has a trailing `/`, otherwise `false`
349
- #
350
- def directory_path?(uri_path)
351
- uri_path.empty? || uri_path[-1] == "/"
583
+ raise ContentPageNotFound, "Cannot find content page for path -- #{uri_path}"
352
584
  end
353
585
  end
354
586
  end