mango 0.1.1 → 0.5.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. data/.gitignore +6 -0
  2. data/.yardopts +6 -0
  3. data/README.mdown +62 -29
  4. data/Rakefile +62 -0
  5. data/VERSION +1 -0
  6. data/bin/mango +5 -0
  7. data/doc/HISTORY.mdown +71 -0
  8. data/doc/ROAD-MAP.mdown +10 -0
  9. data/lib/mango.rb +7 -0
  10. data/lib/mango/application.rb +334 -0
  11. data/lib/mango/content_page.rb +193 -0
  12. data/lib/mango/dependencies.rb +125 -0
  13. data/lib/mango/flavored_markdown.rb +82 -0
  14. data/lib/mango/rack/debugger.rb +22 -0
  15. data/lib/mango/runner.rb +95 -0
  16. data/lib/mango/templates/Gemfile +4 -0
  17. data/lib/mango/templates/README.md +1 -0
  18. data/lib/mango/templates/config.ru +4 -0
  19. data/lib/mango/templates/content/index.md +5 -0
  20. data/lib/mango/templates/themes/default/public/images/particles.gif +0 -0
  21. data/lib/mango/templates/themes/default/public/javascripts/fireworks.js +546 -0
  22. data/lib/mango/templates/themes/default/public/javascripts/timer.js +5 -0
  23. data/lib/mango/templates/themes/default/public/robots.txt +5 -0
  24. data/lib/mango/templates/themes/default/public/styles/fireworks.css +55 -0
  25. data/lib/mango/templates/themes/default/public/styles/reset.css +54 -0
  26. data/lib/mango/templates/themes/default/styles/screen.sass +17 -0
  27. data/lib/mango/templates/themes/default/views/404.haml +21 -0
  28. data/lib/mango/templates/themes/default/views/layout.haml +20 -0
  29. data/lib/mango/templates/themes/default/views/page.haml +3 -0
  30. data/lib/mango/version.rb +6 -0
  31. data/mango.gemspec +35 -0
  32. data/spec/app_root/content/about/index.haml +1 -0
  33. data/spec/app_root/content/about/us.haml +1 -0
  34. data/spec/app_root/content/engines/haml.haml +7 -0
  35. data/spec/app_root/content/engines/markdown.markdown +7 -0
  36. data/spec/app_root/content/engines/md.md +7 -0
  37. data/spec/app_root/content/engines/mdown.mdown +7 -0
  38. data/spec/app_root/content/index.haml +1 -0
  39. data/spec/app_root/content/override.haml +1 -0
  40. data/spec/app_root/content/page_with_missing_view.haml +4 -0
  41. data/spec/app_root/content/turner+hooch.haml +1 -0
  42. data/spec/app_root/security_hole.haml +1 -0
  43. data/spec/app_root/themes/default/public/default.css +3 -0
  44. data/spec/app_root/themes/default/public/images/index.html +10 -0
  45. data/spec/app_root/themes/default/public/images/ripe-mango.jpg +0 -0
  46. data/spec/app_root/themes/default/public/override +10 -0
  47. data/spec/app_root/themes/default/public/robots.txt +2 -0
  48. data/spec/app_root/themes/default/public/styles/override.css +3 -0
  49. data/spec/app_root/themes/default/public/styles/reset.css +27 -0
  50. data/spec/app_root/themes/default/public/styles/subfolder/another.css +3 -0
  51. data/spec/app_root/themes/default/security_hole.sass +1 -0
  52. data/spec/app_root/themes/default/security_hole.txt +1 -0
  53. data/spec/app_root/themes/default/styles/override.sass +2 -0
  54. data/spec/app_root/themes/default/styles/screen.sass +13 -0
  55. data/spec/app_root/themes/default/styles/subfolder/screen.sass +12 -0
  56. data/spec/app_root/themes/default/views/404.haml +7 -0
  57. data/spec/app_root/themes/default/views/layout.haml +7 -0
  58. data/spec/app_root/themes/default/views/page.haml +4 -0
  59. data/spec/mango/application/routing_content_pages_spec.rb +357 -0
  60. data/spec/mango/application/routing_public_files_spec.rb +181 -0
  61. data/spec/mango/application/routing_style_sheets_spec.rb +286 -0
  62. data/spec/mango/application_spec.rb +34 -0
  63. data/spec/mango/content_page/finding_spec.rb +213 -0
  64. data/spec/mango/content_page/initializing_spec.rb +298 -0
  65. data/spec/mango/content_page_spec.rb +44 -0
  66. data/spec/mango/dependencies_spec.rb +189 -0
  67. data/spec/mango/flavored_markdown_spec.rb +52 -0
  68. data/spec/mango/rack/debugger_spec.rb +114 -0
  69. data/spec/mango/version_spec.rb +18 -0
  70. data/spec/quality_spec.rb +32 -0
  71. data/spec/spec.opts +3 -0
  72. data/spec/spec_helper.rb +18 -0
  73. data/spec/support/matchers/malformed_whitespace_matchers.rb +60 -0
  74. metadata +304 -17
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ .DS_Store
2
+ .rvmrc
3
+ .yardoc
4
+ *.gem
5
+ *.tmproj
6
+ yardoc
data/.yardopts ADDED
@@ -0,0 +1,6 @@
1
+ --output-dir ./yardoc
2
+ --markup markdown
3
+ -
4
+ LICENSE
5
+ doc/HISTORY.mdown
6
+ doc/ROAD-MAP.mdown
data/README.mdown CHANGED
@@ -2,65 +2,84 @@
2
2
 
3
3
  Image courtesy of [B.C. Tree Fruits LTD.](http://www.bctree.com/products/sourced/mango.php)
4
4
 
5
- Mango release 0.1.1 (June 15, 2010)
6
- ===================================
5
+ Mango release 0.5.0 (September 12, 2010)
6
+ ========================================
7
7
 
8
8
  Copyright (c) 2010 Ryan Sobol. Licensed under the MIT license. Please see the {file:LICENSE} for more information.
9
9
 
10
- **Source Code**: [http://github.com/ryansobol/mango](http://github.com/ryansobol/mango)
11
- **Bug Tracker**: [http://github.com/ryansobol/mango/issues](http://github.com/ryansobol/mango/issues)
12
- **Wiki**: [http://wiki.github.com/ryansobol/mango](http://wiki.github.com/ryansobol/mango)
10
+ * **Source Code**: [http://github.com/ryansobol/mango](http://github.com/ryansobol/mango)
11
+ * **Documentation**: [http://rubydoc.info/github/ryansobol/mango](http://rubydoc.info/github/ryansobol/mango)
12
+ * **Bug Tracker**: [http://github.com/ryansobol/mango/issues](http://github.com/ryansobol/mango/issues)
13
+ * **Wiki**: [http://wiki.github.com/ryansobol/mango](http://wiki.github.com/ryansobol/mango)
14
+
15
+ **Mango respects [Semantic Versioning](http://semver.org/)!**
13
16
 
14
17
  WHAT'S NEW?
15
18
  -----------
16
19
 
17
- * Reserved the 'mango' namespace on RubyGems.org!
20
+ ### New Features:
21
+
22
+ * Added the beginnings of a default theme titled "Smashing Mangos".
23
+ * Added `Mango::Rack::Debugger` to the middleware stack (Only loads in the `:development` rack environment).
24
+ * Added a `Mango::ContentPage` model to convert user-generated content into HTML. Supports either [Haml](http://haml-lang.com/) or [Markdown](http://daringfireball.net/projects/markdown/syntax) formatted content.
25
+ * Refactored `Mango::Application` to utilize `Mango::ContentPage`. Now views have access to a `@content_page` instance variable.
26
+ * Added `Mango::FlavoredMarkdown`, a subset of [GithubFlavoredMarkdown](http://github.github.com/github-flavored-markdown/), into the Markdown-to-HTML conversion.
27
+
28
+ ### Dependencies:
29
+
30
+ * Updated [Haml](http://haml-lang.com/) to 3.0.18
31
+ * Updated [YARD::Sinatra](http://github.com/rkh/yard-sinatra) to 0.5.0
32
+ * Added [BlueCloth](http://deveiate.org/projects/BlueCloth) 2.0.7 as a required dependency
18
33
 
19
34
  Please see {file:doc/HISTORY.mdown} for the historical overview of the project.
20
35
 
21
36
  SYNOPSIS
22
37
  --------
23
38
 
24
- **Mango is a dynamic blog engine for Ruby hackers who believe in minimalism.**
25
-
26
- Mango let's you use publish to the web using the tools you're already familiar with -- the file system and your trusty text editor. With Mango, there is:
27
-
28
- * No clunky administrator interface for managing content
29
- * No unchangeable database requirements -- no database period!
30
- * No know exploits ;)
39
+ **Mango is a dynamic, database-free, and open source website framework that is designed to make life easier for small teams of designers, developers, and content writers.**
31
40
 
32
41
  FEATURES
33
42
  --------
34
43
 
35
- * Dynamically route HTTP requests to Haml content pages
36
- * Route unknown pages to a customizable 404 page
37
- * Wrap content pages within customizable Haml templates and layout
38
- * Publish to any Rack-based application server (e.g. Phusion Passenger, thin, mongrel, webrick, etc.)
44
+ 1. Easy to install: Mango installs as a RubyGem and can generate a basic website structure in seconds.
45
+
46
+ 2. Easy to publish: Supports many types of deployments like direct SFTP uploading and source control systems like Git, Mercurial, SVN, CSV, etc.
47
+
48
+ 3. Easy to write: Mango let's you publish to the web using the tools you're already familiar with -- the file system and your trusty text editor. Mango supports a variety of formats include Markdown, HAML, HTML, SASS, CSS, and JavaScript. These files are easier to create and revise then working with database records. Say goodbye to clunky administrator interfaces for managing content!
49
+
50
+ 4. Easy to deploy: There's no database to install, configure, and manage.
51
+
52
+ 5. Easy to understand: Mango is perfect for smalls teams of varying levels of coding expertise. Why not take the simple route where everyone is on the same page? Instead of struggling with complex platforms, which most CMS are, Mango is perfect for people who has no coding experience.
53
+
54
+ 6. Easy on the wallet: It's free!
55
+
56
+ 7. Easy to... SPEED: A major advantage of a database-less website framework is speed. Database queries slow down servers. On a high traffic website, this has a dramatic effect on the speed of the site. With minimal server side scripting and zero database queries, Mango is lightening fast.
39
57
 
40
58
  REQUIREMENTS
41
59
  ------------
42
60
 
43
61
  **Required dependencies**
44
62
 
45
- * Ruby 1.9.1
46
- * Rack 1.2.1
47
- * Sinatra 1.0
48
- * Haml 3.0.12
63
+ * [Ruby](http://www.ruby-lang.org/) 1.9.1
64
+ * [Rack](http://rack.rubyforge.org/) 1.2.1
65
+ * [Sinatra](http://www.sinatrarb.com/) 1.0
66
+ * [Haml](http://haml-lang.com/) 3.0.18
67
+ * [Sass](http://sass-lang.com/) 3.0.18 (bundled with Haml)
68
+ * [BlueCloth](http://deveiate.org/projects/BlueCloth) 2.0.7
49
69
 
50
70
  **Optional development dependencies**
51
71
 
52
- * Rake 0.8.7 (bundled with Ruby 1.9.1)
53
- * Rack::Test 0.5.4
54
- * RSpec 1.3.0
55
- * YARD 0.5.5
56
- * BlueCloth 2.0.7
72
+ * [Rake](http://rake.rubyforge.org/) 0.8.7 (bundled with Ruby)
73
+ * [Rack::Test](http://github.com/brynary/rack-test) 0.5.4
74
+ * [RSpec](http://rspec.info/) 1.3.0
75
+ * [YARD](http://yardoc.org/) 0.5.8
76
+ * [YARD::Sinatra](http://github.com/rkh/yard-sinatra) 0.5.0
77
+ * [BlueCloth](http://deveiate.org/projects/BlueCloth) 2.0.7
57
78
 
58
79
  INSTALLING
59
80
  ----------
60
81
 
61
- $ git clone git@github.com:ryansobol/mango.git
62
- $ cd mango
63
- $ bundle install
82
+ $ gem install mango
64
83
 
65
84
  USAGE
66
85
  -----
@@ -75,6 +94,11 @@ USAGE
75
94
  `-- themes
76
95
  `-- default
77
96
  |-- public
97
+ | |-- images
98
+ | | `-- ripe-mango.jpg
99
+ | `-- robots.txt
100
+ |-- styles
101
+ | `-- screen.sass
78
102
  `-- views
79
103
  |-- 404.haml
80
104
  |-- layout.haml
@@ -84,6 +108,15 @@ USAGE
84
108
 
85
109
  $ rackup
86
110
 
111
+ UNDER THE HOOD
112
+ --------------
113
+
114
+ * Mango tries to route HTTP requests to static files first
115
+ * Then it tries to route HTTP requests to Markdown or Haml content pages or Sass style templates
116
+ * Finally, it routes unknown HTTP requests to a customizable 404 page
117
+ * Wraps content pages within a customizable Haml template and layout
118
+ * Supports any Rack-based application server (e.g. Phusion Passenger, thin, mongrel, webrick, etc.)
119
+
87
120
  MOTIVATION
88
121
  ----------
89
122
 
data/Rakefile ADDED
@@ -0,0 +1,62 @@
1
+ # encoding: UTF-8
2
+ require_relative "lib/mango"
3
+ Mango::Dependencies.warn_at_exit
4
+
5
+ ###################################################################################################
6
+
7
+ begin
8
+ require "spec/rake/spectask"
9
+ require "rack/test" # for Rack support
10
+ Spec::Rake::SpecTask.new(:spec)
11
+ task :default => :spec
12
+ rescue LoadError => e
13
+ Mango::Dependencies.create_warning_for(e)
14
+ end
15
+
16
+ ###################################################################################################
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
+ namespace :gem do
32
+ desc "Builds a gem from the current project's Gem::Specification"
33
+ task :build do
34
+ system "gem build mango.gemspec"
35
+ end
36
+
37
+ desc "Removes the gem file for the current project"
38
+ task :clean do
39
+ jeweler { |gem_file| rm gem_file }
40
+ end
41
+
42
+ desc "Pushes the current gem to RubyGems.org"
43
+ task :push do
44
+ jeweler { |gem_file| system "gem push #{gem_file}"}
45
+ end
46
+
47
+ desc "Builds, pushes, and cleans a gem for the current project"
48
+ task :release do
49
+ Rake::Task["gem:build"].invoke
50
+ Rake::Task["gem:push"].invoke
51
+ Rake::Task["gem:clean"].invoke
52
+ end
53
+
54
+ def jeweler(&block)
55
+ file = "mango-#{Mango::VERSION}.gem"
56
+ if File.exists?(file)
57
+ yield file
58
+ else
59
+ puts "No gem file found - #{file}"
60
+ end
61
+ end
62
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.5.0.beta1
data/bin/mango ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require_relative "../lib/mango/runner"
5
+ Mango::Runner.start
data/doc/HISTORY.mdown ADDED
@@ -0,0 +1,71 @@
1
+ Mango release 0.5.0 (September 12, 2010)
2
+ ========================================
3
+
4
+
5
+ Mango release 0.4.0 (August 30, 2010)
6
+ =====================================
7
+
8
+ ### New Features:
9
+
10
+ * Added the beginnings of a default theme titled "Smashing Mangos".
11
+ * Added `Mango::Rack::Debugger` to the middleware stack (Only loads in the `:development` rack environment).
12
+ * Added a `Mango::ContentPage` model to convert user-generated content into HTML. Supports either [Haml](http://haml-lang.com/) or [Markdown](http://daringfireball.net/projects/markdown/syntax) formatted content.
13
+ * Refactored `Mango::Application` to utilize `Mango::ContentPage`. Now views have access to a `@content_page` instance variable.
14
+ * Added `Mango::FlavoredMarkdown`, a subset of [GithubFlavoredMarkdown](http://github.github.com/github-flavored-markdown/), into the Markdown-to-HTML conversion.
15
+
16
+ ### Dependencies:
17
+
18
+ * Updated [Haml](http://haml-lang.com/) to 3.0.18
19
+ * Updated [YARD::Sinatra](http://github.com/rkh/yard-sinatra) to 0.5.0
20
+ * Added [BlueCloth](http://deveiate.org/projects/BlueCloth) 2.0.7 as a required dependency
21
+
22
+ Mango release 0.3.0 (June 25, 2010)
23
+ ===================================
24
+
25
+ ### New Features:
26
+
27
+ * Added a route handler that renders [Sass](http://sass-lang.com/) templates to CSS!
28
+ * Refactored tests for better spec coverage of route handling
29
+ * Massive rewrite of internal documentation thanks to the [YARD::Sinatra (modified)](http://github.com/ryansobol/yard-sinatra)
30
+ * Uploaded developer documentation to [http://yardoc.org/docs/ryansobol-mango](http://yardoc.org/docs/ryansobol-mango)
31
+
32
+ ### Dependencies:
33
+
34
+ * Updated [Haml](http://haml-lang.com/) to 3.0.13
35
+ * Added [YARD::Sinatra](http://github.com/rkh/yard-sinatra) 0.4.0.1 [(modified)](http://github.com/ryansobol/yard-sinatra)
36
+
37
+ ### Bug fixes:
38
+
39
+ * Fixed Regex when parsing LoadError messages on missing development dependencies
40
+ * Fixed rspec gem name detection when requiring spec/rake/spectask in the Rakefile
41
+
42
+ Mango release 0.2.1 (June 23, 2010)
43
+ ===================================
44
+
45
+ * Refactored the application to reduce its code size and increase its maintainability
46
+ * Improved the application's documentation and tests with additional HTTP routing examples
47
+
48
+ Mango release 0.2.0 (June 19, 2010)
49
+ ===================================
50
+
51
+ * Mango tries to route HTTP requests to static files first
52
+ * Then it tries to route HTTP requests to Haml content pages
53
+ * Finally, it routes unknown HTTP requests to a customizable 404 page
54
+
55
+ Mango release 0.1.1 (June 15, 2010)
56
+ ===================================
57
+
58
+ * Reserved the 'mango' namespace on RubyGems.org!
59
+
60
+ Mango release 0.1.0 (June 15, 2010)
61
+ ===================================
62
+
63
+ * Mango tries to route HTTP requests to Haml content pages first
64
+ * Then it routes unknown HTTP requests to a customizable 404 page
65
+ * Wraps content pages within a customizable Haml template and layout
66
+ * Supports any Rack-based application server (e.g. Phusion Passenger, thin, mongrel, webrick, etc.)
67
+
68
+ Mango unrelease 0.0.1 (June 12, 2010)
69
+ =====================================
70
+
71
+ * First commit of the project
@@ -0,0 +1,10 @@
1
+ Road-map of Potential Improvements
2
+ ==================================
3
+
4
+ In no particular order of importance:
5
+
6
+ Mango::Dependencies
7
+ -------------------
8
+
9
+ * Compare, contrast, extend, and/or integrate with Bundler
10
+ * Promote the installation and use of RVM
data/lib/mango.rb ADDED
@@ -0,0 +1,7 @@
1
+ # encoding: UTF-8
2
+ require_relative "mango/dependencies" # ruby version guard
3
+ require_relative "mango/version"
4
+ require_relative "mango/rack/debugger"
5
+ require_relative "mango/application"
6
+ require_relative "mango/flavored_markdown"
7
+ require_relative "mango/content_page"
@@ -0,0 +1,334 @@
1
+ # encoding: UTF-8
2
+ require "sinatra/base"
3
+ require "haml"
4
+ require "sass"
5
+
6
+ module Mango
7
+ # It's probably no surprise that `Mango::Application` is a modular **application controller**
8
+ # class, inheriting all of the magic and wonder of `Sinatra::Base`. The primary responsibility
9
+ # of the class is to receive an HTTP request and send an HTML response by instructing the
10
+ # necessary models and/or views to perform actions based on that request.
11
+ #
12
+ # For **every HTTP request**, the application will first attempt to match the request URI path to
13
+ # a public file found within `settings.public` and send that file with a 200 response code.
14
+ #
15
+ # In addition to serving static assets, the application has two dynamic route handlers:
16
+ #
17
+ # * Content page templates with `GET *`
18
+ # * Style sheet templates with `GET /styles/*.css`
19
+ #
20
+ # and one error handler:
21
+ #
22
+ # * 404 Page Not Found with `NOT_FOUND`
23
+ #
24
+ # # Serving public files found within `settings.public`
25
+ #
26
+ # ### Example requests routed to public files (with potential security holes)
27
+ #
28
+ # |-- content
29
+ # | `-- override.haml
30
+ # `-- themes
31
+ # `-- default
32
+ # |-- public
33
+ # | |-- images
34
+ # | | |-- index.html
35
+ # | | `-- ripe-mango.jpg
36
+ # | |-- override
37
+ # | `-- robots.txt
38
+ # `-- security_hole.txt
39
+ #
40
+ # GET /robots.txt => 200 themes/default/public/robots.txt
41
+ # GET /images/index.html => 200 themes/default/public/images/index.html
42
+ # GET /images/ripe-mango.jpg => 200 themes/default/public/images/ripe-mango.jpg
43
+ # GET /override => 200 themes/default/public/override
44
+ # GET /images/ => 200 themes/default/public/images/index.html
45
+ #
46
+ # GET /../security_hole.txt => pass to NOT_FOUND error handler
47
+ #
48
+ # # Content page templates with `GET *`
49
+ #
50
+ # ### Example `GET *` requests routed to content pages (with potential security holes)
51
+ #
52
+ # |-- content
53
+ # | |-- about
54
+ # | | |-- index.haml
55
+ # | | `-- us.haml
56
+ # | |-- index.haml
57
+ # | |-- override.haml
58
+ # | `-- turner+hooch.haml
59
+ # `-- security_hole.haml
60
+ #
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 /about/us => 200 content/about/us.haml
67
+ # GET /turner%2Bhooch => 200 content/turner+hooch.haml
68
+ #
69
+ # GET /page_not_found => pass to NOT_FOUND error handler
70
+ # GET /../security_hole => pass to NOT_FOUND error handler
71
+ #
72
+ # # Style sheet templates with `GET /styles/*.css`
73
+ #
74
+ # ### Example `GET /styles/*.css` requests routed to style sheets (with potential security holes)
75
+ #
76
+ # `-- themes
77
+ # `-- default
78
+ # |-- public
79
+ # | |-- default.css
80
+ # | `-- styles
81
+ # | |-- override.css
82
+ # | |-- reset.css
83
+ # | `-- subfolder
84
+ # | `-- another.css
85
+ # |-- security_hole.sass
86
+ # `-- styles
87
+ # |-- override.sass
88
+ # |-- screen.sass
89
+ # `-- subfolder
90
+ # `-- screen.sass
91
+ #
92
+ # GET /styles/screen.css => 200 themes/default/styles/screen.sass
93
+ # GET /styles/subfolder/screen.css => 200 themes/default/styles/subfolder/screen.sass
94
+ #
95
+ # GET /styles/reset.css => 200 themes/default/public/styles/reset.css
96
+ # GET /styles/override.css => 200 themes/default/public/styles/override.css
97
+ # GET /default.css => 200 themes/default/public/default.css
98
+ # GET /styles/subfolder/another.css => 200 themes/default/public/styles/subfolder/another.css
99
+ #
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
103
+ #
104
+ # # 404 Page Not Found with `NOT_FOUND`
105
+ #
106
+ # 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.
108
+ #
109
+ 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") }
116
+
117
+ # Renders the `404.haml` template found within `settings.views` and sends it with 404 HTTP
118
+ # response.
119
+ #
120
+ # The `404.haml` template is **not** wrapped within the `layout.haml` template when rendered,
121
+ # even if one exists within `settings.views`.
122
+ #
123
+ # For example:
124
+ #
125
+ # |-- content
126
+ # | `-- index.haml
127
+ # `-- themes
128
+ # `-- default
129
+ # `-- views
130
+ # `-- 404.haml
131
+ #
132
+ # GET /page_not_found => 404 themes/default/views/404.haml
133
+ #
134
+ not_found do
135
+ haml :"404", :layout => false
136
+ end
137
+
138
+ # Attempts to render style sheet templates found within `settings.styles`
139
+ #
140
+ # First, the application attempts to match the URI path with a public CSS file stored in
141
+ # `settings.public`. If a public CSS file is found, the handler will:
142
+ #
143
+ # * Send the public CSS file with a 200 HTTP response code
144
+ # * Halt execution
145
+ #
146
+ # For example:
147
+ #
148
+ # `-- themes
149
+ # `-- default
150
+ # `-- public
151
+ # `-- styles
152
+ # `-- reset.css
153
+ #
154
+ # GET /styles/reset.css => 200 themes/default/public/styles/reset.css
155
+ #
156
+ # If no match is found, the route handler attempts to match the URI path with a style sheet
157
+ # template stored in `settings.styles`. If a style sheet template is found, the handler will:
158
+ #
159
+ # * Convert the style sheet template from Sass to CSS
160
+ # * Send the converted style with a 200 HTTP response code
161
+ # * Halt execution
162
+ #
163
+ # For example:
164
+ #
165
+ # `-- themes
166
+ # `-- default
167
+ # `-- styles
168
+ # `-- screen.sass
169
+ #
170
+ # GET /styles/screen.css => 200 themes/default/styles/screen.sass
171
+ #
172
+ # **It's intended that requests to public CSS files and requests to style sheet templates share
173
+ # the `/styles/` prefix.**
174
+ #
175
+ # Finally, if no matches are found, the route handler passes execution to the `NOT_FOUND` error
176
+ # handler.
177
+ #
178
+ get "/styles/*.css" do |uri_path|
179
+ render_style_sheet! uri_path
180
+ not_found
181
+ end
182
+
183
+ ###############################################################################################
184
+
185
+ private
186
+
187
+ # Given a URI path, attempts to render a style sheet, if it exists, and halt
188
+ #
189
+ # @param [String] uri_path
190
+ #
191
+ def render_style_sheet!(uri_path)
192
+ styles_match = File.join(settings.styles, "*")
193
+ style_sheet_path = build_style_sheet_path(uri_path)
194
+
195
+ return unless File.fnmatch(styles_match, style_sheet_path)
196
+ return unless File.file?(style_sheet_path)
197
+
198
+ content_type "text/css"
199
+ halt sass(uri_path.to_sym, :views => settings.styles)
200
+ end
201
+
202
+ # Given a URI path, build a path to a potential style sheet
203
+ #
204
+ # @param [String] uri_path
205
+ # @param [String] format (defaults to `sass`)
206
+ # @return [String] The path to a potential style sheet
207
+ #
208
+ def build_style_sheet_path(uri_path, format = "sass")
209
+ File.expand_path("#{uri_path}.#{format}", settings.styles)
210
+ end
211
+
212
+ public
213
+
214
+ # Attempts to render content page templates found within `settings.content`
215
+ #
216
+ # First, the application attempts to match the URI path with a public file stored in
217
+ # `settings.public`. If a public file is found, the handler will:
218
+ #
219
+ # * Send the public file with a 200 HTTP response code
220
+ # * Halt execution
221
+ #
222
+ # For example:
223
+ #
224
+ # `-- themes
225
+ # `-- default
226
+ # `-- public
227
+ # `-- hello_word.html
228
+ #
229
+ # GET /hello_word.html => 200 themes/default/public/hello_word.html
230
+ #
231
+ # If no match is found, the route handler attempts to match the URI path with a content page
232
+ # template stored in `settings.content`. If a content page template is found, the handler will:
233
+ #
234
+ # * Read the content page into memory and assign it to the `@content_page` instance variable
235
+ # * Render the content page's view template file (see `Mango::ContentPages`)
236
+ # * A `RuntimeError` is raised if the view template does not exist within `settings.views`
237
+ # * Send the rendered page with a 200 HTTP response code and halt execution
238
+ #
239
+ # In addition, if a `layout.haml` template exists within `settings.views`, the page's view
240
+ # template is wrapped within this layout when rendered.
241
+ #
242
+ # For example:
243
+ #
244
+ # |-- content
245
+ # | `-- index.haml
246
+ # `-- themes
247
+ # `-- default
248
+ # `-- views
249
+ # |-- layout.haml
250
+ # `-- page.haml
251
+ #
252
+ # GET /index => 200 content/index.haml +
253
+ # themes/default/views/page.haml +
254
+ # themes/default/views/layout.haml
255
+ #
256
+ # Finally, if no matches are found, the route handler passes execution to the `NOT_FOUND` error
257
+ # handler.
258
+ #
259
+ get "/*" do |uri_path|
260
+ render_index_file! uri_path
261
+ render_content_page! uri_path
262
+ not_found
263
+ end
264
+
265
+ ###############################################################################################
266
+
267
+ private
268
+
269
+ # Given a URI path, attempts to send an index.html file, if it exists, and halt
270
+ #
271
+ # @param [String] uri_path
272
+ #
273
+ def render_index_file!(uri_path)
274
+ return unless uri_path[-1] == "/"
275
+
276
+ index_match = File.join(settings.public, "*")
277
+ index_file_path = build_index_file_path(uri_path)
278
+
279
+ return unless File.fnmatch(index_match, index_file_path)
280
+ return unless File.file?(index_file_path)
281
+
282
+ send_file index_file_path
283
+ end
284
+
285
+ # Given a URI path, build a path to a potential index.html file
286
+ #
287
+ # @param [String] uri_path
288
+ # @return [String] The path to a potential index.html file
289
+ #
290
+ def build_index_file_path(uri_path)
291
+ uri_path = File.join(uri_path, "index.html")
292
+ File.expand_path(uri_path, settings.public)
293
+ end
294
+
295
+ ###############################################################################################
296
+
297
+ private
298
+
299
+ # Given a URI path, attempts to render a content page, if it exists, and halt
300
+ #
301
+ # @param [String] uri_path
302
+ # @raise [RuntimeError] Raised when the content page's view template cannot be found
303
+ #
304
+ def render_content_page!(uri_path)
305
+ content_match = File.join(settings.content, "*")
306
+ content_page_path = build_content_page_path(uri_path)
307
+ return unless File.fnmatch(content_match, content_page_path)
308
+
309
+ begin
310
+ @content_page = Mango::ContentPage.find_by_path(content_page_path)
311
+ rescue Mango::ContentPage::PageNotFound
312
+ return
313
+ end
314
+
315
+ begin
316
+ halt haml(@content_page.view)
317
+ rescue Errno::ENOENT
318
+ view_path = File.expand_path("#{@content_page.view}.haml", settings.views)
319
+ raise "Unable to find a view template file -- #{view_path}"
320
+ end
321
+ end
322
+
323
+ # Given a URI path, build a path to a potential content page
324
+ #
325
+ # @param [String] uri_path
326
+ # @return [String] The path to a potential content page
327
+ #
328
+ def build_content_page_path(uri_path)
329
+ uri_path += "index" if uri_path.empty? || uri_path[-1] == "/"
330
+ File.expand_path(uri_path, settings.content)
331
+ end
332
+
333
+ end
334
+ end