├── .gems ├── .gitignore ├── .yardopts ├── AUTHORS ├── Gemfile ├── HISTORY.md ├── LICENSE ├── README.md ├── Rakefile ├── Scribefile ├── TODO.md ├── bin └── proton ├── data ├── new_site │ ├── .gitignore │ ├── Protonfile │ ├── README.md │ ├── _layouts │ │ └── default.haml │ └── index.haml └── rack │ ├── Gemfile │ └── config.ru ├── lib ├── proton.rb └── proton │ ├── cacheable.rb │ ├── cli.rb │ ├── cli │ └── helpers.rb │ ├── compass_support.rb │ ├── config.rb │ ├── helpers.rb │ ├── layout.rb │ ├── meta.rb │ ├── page.rb │ ├── partial.rb │ ├── project.rb │ ├── server.rb │ ├── set.rb │ └── version.rb ├── manual ├── config.ru ├── contents.haml ├── extending.md ├── extending │ ├── adding_commands.md │ └── creating_extensions.md ├── helpers.md ├── index.textile ├── introduction.md ├── introduction │ ├── config.md │ ├── getting_started.md │ ├── installation.md │ ├── layouts.md │ ├── metadata.md │ ├── partials.md │ └── template_languages.md ├── proton_build.md ├── proton_create.md ├── proton_rack.md ├── proton_start.md ├── tips.md └── tips │ ├── simple_folder_structure.md │ ├── subclassing_page.md │ └── tilt_build_options.md ├── proton.gemspec └── test ├── fixture ├── build_options │ ├── control │ │ ├── page.html │ │ └── style.css │ ├── hyde.conf │ └── site │ │ ├── page.haml │ │ └── style.scss ├── compass │ ├── hyde.conf │ └── site │ │ └── style.scss ├── empty_config │ └── hyde.conf ├── extensions │ ├── control │ │ └── index.html │ ├── extensions │ │ ├── a │ │ │ └── a.rb │ │ └── hi.rb │ ├── hyde.conf │ └── site │ │ └── index.haml ├── fail_type │ ├── control │ │ ├── about │ │ │ ├── index.html │ │ │ └── us.html │ │ └── index.html │ ├── hyde.conf │ └── site │ │ └── index.haml ├── high_version │ └── hyde.conf ├── high_version_2 │ └── hyde.conf ├── html │ ├── control │ │ └── index.html │ ├── hyde.conf │ └── site │ │ └── index.html ├── ignores │ ├── control │ │ └── about.html │ ├── hyde.conf │ └── site │ │ ├── about.haml │ │ └── hi.haml ├── metadata │ ├── control │ │ └── index.html │ ├── hyde.conf │ └── site │ │ └── index.haml ├── nested_layout │ ├── control │ │ └── index.html │ ├── hyde.conf │ ├── layouts │ │ ├── default.haml │ │ └── post.haml │ └── site │ │ └── index.haml ├── one │ ├── control │ │ ├── about │ │ │ ├── index.css │ │ │ └── us.html │ │ ├── cheers.html │ │ ├── css │ │ │ ├── bar.css │ │ │ └── style.css │ │ ├── hello.html │ │ ├── hi.html │ │ ├── images │ │ │ ├── bar.gif │ │ │ ├── baz.png │ │ │ └── foo.jpg │ │ └── index.html │ ├── hyde.conf │ ├── layouts │ │ └── default.haml │ ├── partials │ │ └── menu.haml │ └── site │ │ ├── about │ │ ├── index.scss │ │ └── us.haml │ │ ├── cheers.html.haml │ │ ├── css │ │ ├── bar.scss │ │ └── style.scss │ │ ├── hello.haml │ │ ├── hi.html │ │ ├── images │ │ ├── bar.gif │ │ ├── baz.png │ │ └── foo.jpg │ │ └── index.haml ├── parent │ ├── control │ │ ├── about │ │ │ ├── index.html │ │ │ └── us.html │ │ └── index.html │ ├── hyde.conf │ └── site │ │ ├── about │ │ ├── index.haml │ │ └── us.haml │ │ └── index.haml ├── sort │ ├── control │ │ ├── about.html │ │ └── about │ │ │ ├── hardy.html │ │ │ └── intrepid.html │ ├── hyde.conf │ └── site │ │ ├── about.haml │ │ └── about │ │ ├── hardy.haml │ │ └── intrepid.haml └── subclass │ ├── control │ └── index.html │ ├── extensions │ └── a │ │ └── a.rb │ ├── hyde.conf │ ├── layouts │ ├── default.haml │ └── post.haml │ └── site │ └── index.haml ├── helper.rb └── unit ├── build_options_test.rb ├── extensions_test.rb ├── fixture_test.rb ├── helper_test.rb ├── page_test.rb ├── proton_test.rb └── set_test.rb /.gems: -------------------------------------------------------------------------------- 1 | # To install these... 2 | # ...with Monk: monk install 3 | # ...with RVM: cat .gems | grep -v \# | xargs gem install 4 | # ...otherwise: cat .gems | grep -v \# | xargs sudo gem install 5 | 6 | shake -v "~> 0.1" 7 | tilt -v ">= 1.2.2" 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | .rvmrc 3 | test/fixture/*/public/ 4 | doc/ 5 | .yardoc 6 | *.gem 7 | /Gemfile.lock 8 | /manual/Gemfile.lock 9 | 10 | -------------------------------------------------------------------------------- /.yardopts: -------------------------------------------------------------------------------- 1 | --files="manual/*/*" 2 | --files="README.md" 3 | --files="HISTORY.md" 4 | --files="AUTHORS" 5 | --main="manual/Hyde.md" 6 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Credits 2 | ======= 3 | 4 | Hyde was created and being developed and maintained by Rico Sta. Cruz of Sinefunc, Inc. 5 | 6 | A hat tip goes to Tom Preston-Werner (mojombo) for Jekyll, the very project that inspired Hyde. 7 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source :rubygems 2 | gemspec 3 | -------------------------------------------------------------------------------- /HISTORY.md: -------------------------------------------------------------------------------- 1 | Proton v0.3.4 - Aug 01, 2011 2 | ---------------------------- 3 | 4 | ### Added: 5 | * __Speedup by at least 8x__ by implementing smarter caching. 6 | 7 | ### Fixed: 8 | * Stop adding a 'Gemfile.lock' file when doing 'proton rack'. 9 | 10 | ### Misc: 11 | * Update documentation rake tasks. 12 | * Upgrade Tilt to v1.3.2. 13 | * Use the HTML5 doctype in the default site. 14 | 15 | Proton v0.3.3 - Jul 14, 2011 16 | ---------------------------- 17 | 18 | Small fixes again. 19 | 20 | ### Added: 21 | * a confirmation message when running 'proton rack'. 22 | 23 | ### Changed: 24 | * the default site to read 'Proton' instead of 'Hyde' in the default title. 25 | * Update 'proton rack' to generate Gemfile.lock. 26 | 27 | Proton v0.3.2 - Jun 22, 2011 28 | ---------------------------- 29 | 30 | Hotfixes. 31 | 32 | ### Fixed: 33 | * `Gemfile` and `Gemfile.lock` are now auto ignored when doing *proton build*. 34 | * Fixed the `rel()` helper. 35 | 36 | Proton v0.3.0 - Jun 22, 2011 37 | ---------------------------- 38 | 39 | **The project has been renamed to Proton** (previously called *Hyde*). 40 | 41 | A manual is also in progress, currently hosted at 42 | [sinefunc.com/hyde/manual](http://sinefunc.com/hyde/manual). 43 | 44 | ### Renamed: 45 | * * The main class is now called `Proton` instead of `Hyde`. However, *Hyde* 46 | still works as an alias. 47 | * The main executable is now called `proton` (and not `hyde`). 48 | * The configuration file is now called `Protonfile`. The legacy *hyde.conf* 49 | and *.hyderc* still works for backward-compatibility. 50 | 51 | ### Added: 52 | * New `proton rack` command to Rackify a given project. 53 | 54 | ### Changed: 55 | * Creating a project with `proton create` will now not include any gem 56 | manifest or *config.ru* file. 57 | 58 | Hyde v0.2.3 - Jun 20, 2011 59 | -------------------------- 60 | 61 | ### Changed: 62 | * Use a bundler Gemfile for Hyde sites if a Gemfile is found. 63 | 64 | ### Fixed: 65 | * **Fixed `hyde create`.** 66 | * Fixed overriding of Hyde::CLI via commands not working. 67 | * Fixed the rel() helper. 68 | 69 | Hyde v0.2.2 - Jun 16, 2011 70 | -------------------------- 71 | 72 | ### Added: 73 | * **Built-in Compass support.** 74 | * **Enable Sass, SCSS, Haml, Textile and Markdown by default.** 75 | * Extensions from `_extensions/*rb` will now be loaded. 76 | 77 | ### Changed: 78 | * The default `hyde.conf` now comments out the default stuff you don't need to set. 79 | * Update dependencies to Cuba 2.0, and Hashie 1.0. 80 | 81 | Hyde v0.1.14 - Jun 04, 2011 82 | --------------------------- 83 | 84 | ### Fixed: 85 | * Fixed a syntax error in page.rb. 86 | * Don't impose gem versions explicitly, and don't load Rubygems if used as a 87 | library. 88 | 89 | ### Misc: 90 | * Added some doc comments to the main classes. 91 | 92 | Hyde v0.1.13 93 | ------------ 94 | 95 | - Try to fix an edge case where the path '/' gives you an arbitrary dotfile. 96 | 97 | Hyde v0.1.11 98 | ------------ 99 | 100 | - Deprecate in-app caching for rack-cache. 101 | - The Hyde server now sends the Last-Modified HTTP header. 102 | - New Hyde sites will now use rack-cache (optionally) when used as a Rack site. 103 | 104 | Hyde v0.1.10 105 | ------- 106 | 107 | - New Hyde sites will now have a gems manifest. This means you can 108 | push your Hyde sites to Heroku instantly. 109 | - Add cuba to dependencies. 110 | - The server now serves the right MIME types. 111 | - When used as a Rack app, Hyde sends cache headers. 112 | 113 | Hyde v0.1.9 114 | ----------- 115 | 116 | - Hotfix: tilt_build_options should work even if there was no tilt_options specified. 117 | 118 | Hyde v0.1.8 119 | ----------- 120 | 121 | - Fix: 404 pages in 'hyde start' no longer throws an exception log to the viewer. 122 | - Implemented the `content_for` and `yield_content` helpers. 123 | - Fix partial locals not working. 124 | - Allow having the same layouts/partials path as the site. 125 | - Implement `Hyde.project` which returns the latest project. (deprecates $project) 126 | - Support tilt_build_options in the config. 127 | 128 | Hyde v0.1.7 129 | ----------- 130 | 131 | - Show friendlier error messages. 132 | - Show steps on how to install missing gems when any are encountered. 133 | - Change 'hyde build' display format to look better. 134 | 135 | Hyde v0.1.6 136 | ----------- 137 | 138 | - Fix an edge case where files containing '---' somewhere is treated wrong. 139 | - Ruby 1.8 compatibility. 140 | 141 | Hyde v0.1.4 142 | ----------- 143 | 144 | - Fix: `hyde start` was giving errors. 145 | 146 | Hyde v0.1.3 147 | ----------- 148 | 149 | - .html files are now being treated as .erb. 150 | - Implement `page.children.find`. 151 | - Implement `page.children.except`. 152 | - Fix #children and sorting giving errors. 153 | - Fix #siblings. 154 | - Revise the 'no config file found' error message. 155 | - Allow `.hyderc` as a filename. 156 | - Add help for `hyde help start`. 157 | - Support `hyde start -D` which is a very hackish solution to have 158 | Hyde start as a daemon. 159 | 160 | Hyde v0.1.2 161 | ----------- 162 | 163 | - Allow `hyde create .` to add a hyde.conf in the current folder. 164 | - Revamp the help screen. 165 | - Fix: change the default load path for Sass/SCSS to 'css'. 166 | - Add Page#depth. 167 | - Fix Page#breadcrumbs. 168 | - Fix Page#parent. 169 | - Add the `rel` helper. 170 | - Generated Hyde projects are now Rack-compatible. 171 | 172 | Hyde v0.1.1 173 | ----------- 174 | 175 | - Default project is now simpler. The site_path is `.`. 176 | - Implement `Project#build`. 177 | - If YAML parsing of page metadata fails, treat it as content. 178 | - All options in `hyde.conf` are now optional (even `hyde_requirement`). 179 | - Page metadata can now only be a hash. 180 | - Fix `hyde start`. 181 | - Minimum Ruby version is now at 1.8.6. 182 | 183 | Hyde v0.1.0 184 | ----------- 185 | 186 | **Complete rewrite.** Many thing have been deprecated. 187 | 188 | - Now uses Tilt (for templates), Shake (for CLI) and Cuba (for the server). 189 | - Now supports everything Tilt supports: CoffeeScript, Liquid, etc. 190 | - Allow `tilt_options` in hyde.conf. 191 | - Old extensions will be broken (but who made any yet, anyway?) 192 | - Update the `hyde create` template's gitignore file to account for _public. 193 | 194 | Hyde v0.0.8 195 | ----------- 196 | 197 | - Add support for subclassing. (just add a 'type' meta) 198 | - Implement Project#all. 199 | - Implement Page#all and Page#all(type). 200 | - Fix binary files losing extensions on 'hyde build'. 201 | - Allow "layout: false" to ensure that a page doesn't have a layout. 202 | - Fix bug where "index.html.haml" and "index.rss.haml" clash. 203 | - Implement Page#content. 204 | 205 | Hyde v0.0.7 206 | ----------- 207 | 208 | - Add support for Sass and SCSS. 209 | - Add support for ignored files. 210 | 211 | Hyde v0.0.6 212 | ----------- 213 | 214 | - Added support for blocks for `yield_content` (as default text). 215 | - `Page#referrer` now is a page (instead of a string of the name). 216 | - Partials path is now not ignored by default. 217 | - Add support for page ordering (by the `position` key in metadata). 218 | - You can now start an IRB session with the `hyde console` command. 219 | - Implement traversion methods for page: #next, #previous, #siblings, 220 | and #parent. 221 | - Implement the 'page' variable to be available in pages. 222 | - Add Page#title. 223 | - Add Page#path. 224 | - Add Page#breadcrumbs. 225 | - Implement Utils#escape_html. 226 | - Hyde now always tries 'layouts/default.*' as the default layout, if none's 227 | specified. (TODO: layout: false) 228 | - Implement Renderer.layoutable?, which dictates if a renderer is capable of 229 | having a layout. 230 | 231 | Hyde v0.0.5 - 2010-05-30 232 | ------------------------ 233 | 234 | - Implemented `content_for` and `yield_content` helpers 235 | - Added `partials_path` config variable 236 | - Changed helper method `partial`s syntax (from `partial X, :locals => { ... }` to `partial X, ...`) 237 | - Line numbers for errors are shown now 238 | - Added rudimentary 404 page 239 | - Added `hyde_requirement` config variable -- Hyde will now not proceed if the project needs a later version of Hyde 240 | - Extensions are now auto-guessed (for example, 'foo.less' will be accessible as 'foo.css') 241 | 242 | Hyde v0.0.4 - 2010-05-25 243 | ------------------------ 244 | 245 | - First public release 246 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010-2011 Rico Sta. Cruz and Sinefunc, Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Proton](http://sinefunc.com/proton?) 2 | #### Proton is a website preprocessor. 3 | 4 | * Website: http://sinefunc.com/proton/ 5 | * Documentation: http://sinefunc.com/proton/manual 6 | 7 | Authors 8 | ------- 9 | 10 | Authored and maintained by Rico Sta. Cruz and Sinefunc, Inc. 11 | See [sinefunc.com](http://sinefunc.com) for more about our work! 12 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | task :test do 2 | Dir['test/**/*_test.rb'].each { |f| load f } 3 | end 4 | 5 | namespace :doc do 6 | desc "Builds the docs in doc/." 7 | task :update do 8 | # gem install proscribe (~> 0.0.2) 9 | system "proscribe build" 10 | end 11 | 12 | desc "Updates the online manual." 13 | task :deploy => :update do 14 | # http://github.com/rstacruz/git-update-ghpages 15 | system "git update-ghpages sinefunc/proton -i doc --prefix manual" 16 | end 17 | end 18 | 19 | task :default => :test 20 | -------------------------------------------------------------------------------- /Scribefile: -------------------------------------------------------------------------------- 1 | manual: 'manual' 2 | 3 | files: 4 | - source: lib/**/*.rb 5 | 6 | output: doc 7 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | - Caching 2 | - MIME types 3 | 4 | - Post build hooks? 5 | - tilt_build_options 6 | - deprecate $project, implement Hyde.project 7 | -------------------------------------------------------------------------------- /bin/proton: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | $:.push File.expand_path('../../lib', __FILE__) 3 | 4 | require 'rubygems' unless defined?(::Gem) 5 | require 'proton' 6 | 7 | Proton::CLI.run! 8 | -------------------------------------------------------------------------------- /data/new_site/.gitignore: -------------------------------------------------------------------------------- 1 | ## MAC OS 2 | .DS_Store 3 | 4 | ## TEXTMATE 5 | *.tmproj 6 | tmtags 7 | 8 | ## EMACS 9 | *~ 10 | \#* 11 | .\#* 12 | 13 | ## VIM 14 | *.swp 15 | *.swo 16 | *.swn 17 | 18 | ## PROJECT::GENERAL 19 | coverage 20 | rdoc 21 | pkg 22 | 23 | ## PROJECT::SPECIFIC 24 | public 25 | -------------------------------------------------------------------------------- /data/new_site/Protonfile: -------------------------------------------------------------------------------- 1 | # This is a Proton site. 2 | # Install Proton (`gem install proton`) and type `proton` for help. 3 | requirement: 0.2 4 | 5 | # The folder where the site's source files are kept. 6 | site_path: . 7 | output_path: _output 8 | 9 | # Other paths: 10 | layouts_path: _layouts 11 | extensions_path: _extensions 12 | partials_path: . 13 | -------------------------------------------------------------------------------- /data/new_site/README.md: -------------------------------------------------------------------------------- 1 | Instructions 2 | ------------ 3 | 4 | 1. Make sure Ruby (>= v1.8) is installed. 5 | 2. Install the proton gem: `gem install proton` 6 | 3. Build the site HTML files by typing: `proton build` 7 | 8 | (If #2 fails, you may need to type `sudo gem install proton` instead.) 9 | 10 | 11 | -------------------------------------------------------------------------------- /data/new_site/_layouts/default.haml: -------------------------------------------------------------------------------- 1 | !!! 5 2 | %html 3 | %head 4 | %title= page.title 5 | 6 | %meta(charset='UTF-8') 7 | -# Use the latest IE engine, or Chrome frame. 8 | %meta(http-equiv='X-UA-Compatible' content='IE=edge,chrome=1') 9 | 10 | -# Mobile viewport optimization. j.mp/bplateviewport 11 | %meta(name='viewport' content='width=device-width, initial-scale=1.0') 12 | 13 | -# Standard SEO meta 14 | - if page.meta.keywords 15 | %meta{:name => 'keywords', :content => page.meta.keywords} 16 | - if page.meta.description 17 | %meta{:name => 'description', :content => page.meta.description} 18 | 19 | %link{:rel => 'stylesheet', :href => '/css/style.css'} 20 | 21 | %body 22 | #content 23 | != yield 24 | 25 | %div#footer 26 | %hr 27 | %p Generated by Proton 28 | 29 | -------------------------------------------------------------------------------- /data/new_site/index.haml: -------------------------------------------------------------------------------- 1 | layout: default 2 | title: Your new Proton site 3 | -- 4 | %h1 It works! 5 | %p This is your new site. Feel free to take a look around! 6 | -------------------------------------------------------------------------------- /data/rack/Gemfile: -------------------------------------------------------------------------------- 1 | source :rubygems 2 | 3 | gem "proton", "~> 0.3.4" 4 | gem "rack-cache", "~> 1.0.0" 5 | 6 | # CoffeeScript support 7 | # gem "coffee-script", "2.2.0" 8 | 9 | # CoffeeScript support in Heroku 10 | # gem "therubyracer-heroku", "0.8.1.pre3" 11 | -------------------------------------------------------------------------------- /data/rack/config.ru: -------------------------------------------------------------------------------- 1 | # This file exists to make this project Rack-compatible. 2 | # You may delete it if you're not concerned about this. 3 | 4 | require 'rubygems' unless defined?(::Gem) 5 | 6 | # Use Bundler if possible. 7 | begin 8 | require 'bundler' 9 | Bundler.setup 10 | rescue LoadError 11 | gem 'proton', '0.3.2' 12 | end 13 | 14 | # Optional: use the 'rack-cache' gem for cacheing. 15 | if ENV['RACK_ENV'] == 'production' 16 | begin 17 | require 'rack/cache' 18 | use Rack::Cache 19 | rescue LoadError 20 | end 21 | end 22 | 23 | # Load Proton. 24 | require 'proton/server' 25 | Proton::Project.new File.dirname(__FILE__) 26 | run Proton::Server 27 | -------------------------------------------------------------------------------- /lib/proton.rb: -------------------------------------------------------------------------------- 1 | $:.push *Dir[File.expand_path('../../vendor/*/lib', __FILE__)] 2 | 3 | require 'fileutils' 4 | require 'ostruct' 5 | require 'hashie' 6 | require 'yaml' 7 | require 'tilt' 8 | require 'shake' 9 | 10 | # For Compass and such 11 | Encoding.default_external = 'utf-8' if defined?(::Encoding) 12 | 13 | # HTML files as ERB 14 | Tilt.mappings['html'] = Tilt.mappings['erb'] 15 | 16 | # Class: Proton 17 | # The Proton class. 18 | # 19 | # ## Description 20 | # This is the main class. 21 | # 22 | # This class is also aliased as `Hyde` for backward-compatibility with 23 | # versions <= 0.2.x, when the project was still called Hyde. 24 | 25 | class Proton 26 | PREFIX = File.expand_path('../', __FILE__) 27 | 28 | # Class: Proton::Error 29 | # An error. 30 | # 31 | # ## Description 32 | # The class Error describes any error thrown by the application. 33 | # 34 | # ## Example 35 | # 36 | # begin 37 | # Proton::Project.new './my_project/' 38 | # rescue Proton::LegacyError => e 39 | # puts "Old version." 40 | # rescue Proton::VersionError => e 41 | # puts "The project requires a newer version of Proton." 42 | # rescue Proton::Error => e 43 | # puts e 44 | # end 45 | 46 | Error = Class.new(StandardError) 47 | LegacyError = Class.new(Error) 48 | VersionError = Class.new(Error) 49 | 50 | # Constant: CONFIG_FILES (Proton) 51 | # An array of the allowed config filenames. 52 | CONFIG_FILES = ['Protonfile', 'proton.conf', '.protonrc', 'hyde.conf', '.hyderc'] 53 | 54 | autoload :Project, "#{PREFIX}/proton/project" 55 | autoload :Page, "#{PREFIX}/proton/page" 56 | autoload :Meta, "#{PREFIX}/proton/meta" 57 | autoload :Config, "#{PREFIX}/proton/config" 58 | autoload :CLI, "#{PREFIX}/proton/cli" 59 | autoload :Set, "#{PREFIX}/proton/set" 60 | autoload :Layout, "#{PREFIX}/proton/layout" 61 | autoload :Partial, "#{PREFIX}/proton/partial" 62 | autoload :Helpers, "#{PREFIX}/proton/helpers" 63 | autoload :Cacheable, "#{PREFIX}/proton/cacheable" 64 | 65 | require "#{PREFIX}/proton/version" 66 | 67 | class << self 68 | # Attribute: project (Proton) 69 | # Returns the latest project. 70 | # 71 | # ## Example 72 | # Proton.project.path(:site) 73 | 74 | attr_accessor :project 75 | end 76 | end 77 | 78 | # For backward compatibility reasons, Hyde is an alias for Proton. 79 | Hyde = Proton 80 | -------------------------------------------------------------------------------- /lib/proton/cacheable.rb: -------------------------------------------------------------------------------- 1 | class Proton 2 | # Module: Cache 3 | module Cacheable 4 | def self.enable! 5 | @enabled = true 6 | end 7 | 8 | def self.disable! 9 | @enabled = false 10 | end 11 | 12 | def self.enabled?() 13 | !! @enabled 14 | end 15 | 16 | # Enable by default 17 | enable! 18 | 19 | def self.cache(*args) 20 | if enabled? 21 | @cache ||= Hash.new 22 | args = args.map { |s| s.to_s }.join('-') 23 | @cache[args] ||= yield 24 | else 25 | yield 26 | end 27 | end 28 | 29 | def cache_method(*methods) 30 | methods.each do |method| 31 | alias_method :"real_#{method}", method 32 | 33 | class_eval do 34 | define_method(method) { |*args| 35 | id = nil 36 | id ||= self.file if respond_to?(:file) 37 | id ||= self.to_s 38 | 39 | Cacheable.cache self.class, method, id, args do 40 | send :"real_#{method}", *args 41 | end 42 | } 43 | end 44 | end 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /lib/proton/cli.rb: -------------------------------------------------------------------------------- 1 | # Class: Proton::CLI 2 | # Command line runner. 3 | 4 | class Proton 5 | class CLI < Shake 6 | autoload :Helpers, "#{PREFIX}/proton/cli/helpers" 7 | 8 | extend Helpers 9 | include Defaults 10 | 11 | task(:create) do 12 | wrong_usage unless params.size == 1 13 | template = File.expand_path('../../../data/new_site', __FILE__) 14 | target = params.first 15 | 16 | if target == '.' 17 | pass "This is already a Proton project." if @protonfile 18 | FileUtils.cp_r File.join(template, 'Protonfile'), target 19 | say_status :create, 'Protonfile' 20 | pass 21 | end 22 | 23 | pass "Error: target directory already exists." if File.directory?(target) 24 | 25 | puts "Creating files in #{target}:" 26 | puts 27 | 28 | FileUtils.cp_r template, target 29 | Dir[File.join(target, '**', '*')].sort.each do |f| 30 | say_status :create, f if File.file?(f) 31 | end 32 | 33 | puts "" 34 | puts "Done! You've created a new project in #{target}." 35 | puts "Get started now:" 36 | puts "" 37 | puts " $ cd #{target}" 38 | puts " $ #{executable} start" 39 | puts "" 40 | puts "Or build the HTML files:" 41 | puts "" 42 | puts " $ #{executable} build" 43 | puts "" 44 | end 45 | 46 | task.description = "Starts a new Proton project" 47 | task.usage = "create NAME" 48 | task.category = :create 49 | 50 | task(:build) do 51 | pre = project.config.output_path 52 | 53 | project.build { |page| 54 | c, handler = if page.tilt? 55 | [ 33, "#{page.tilt_engine_name.downcase}" ] 56 | else 57 | [ 30, '*' ] 58 | end 59 | 60 | puts ("\033[0;#{c}m%10s\033[0;32m #{pre}\033[0;m%s" % [ handler, page.path ]).strip 61 | } 62 | project.send :build_cleanup 63 | end 64 | 65 | task.description = "Builds the current project" 66 | task.category = :project 67 | 68 | task(:start) do 69 | project 70 | 71 | port = (params.extract('-p') || 4833).to_i 72 | host = (params.extract('-o') || '0.0.0.0') 73 | daemon = (!! params.delete('-D')) 74 | 75 | require 'proton/server' 76 | 77 | if daemon 78 | pid = fork { Proton::Server.run! :Host => host, :Port => port, :quiet => true } 79 | sleep 2 80 | puts 81 | puts "Listening on #{host}:#{port} on pid #{pid}." 82 | puts "To stop: kill #{pid}" 83 | else 84 | Proton::Server.run! :Host => host, :Port => port 85 | end 86 | end 87 | 88 | task.description = "Starts the server" 89 | task.category = :project 90 | task.help = %{ 91 | Usage: 92 | 93 | #{executable} start [-p PORT] [-o HOST] [-D] 94 | 95 | Starts an HTTP server so you may rapidly test your project locally. 96 | 97 | If the -p and/or -o is specified, it will listen on the specified HOST:PORT. 98 | Otherwise, the default is 0.0.0.0:4833. 99 | 100 | If -D is specified, it goes into daemon mode. 101 | }.gsub(/^ {4}/, '').strip.split("\n") 102 | 103 | task(:rack) do 104 | project 105 | 106 | from = File.expand_path("#{PREFIX}/../data/rack/*") 107 | files = Dir[from] 108 | 109 | files.each do |f| 110 | FileUtils.cp f, '.' 111 | say_status :create, File.basename(f) 112 | end 113 | 114 | err "" 115 | err "Done! Your project is now Rack-compatible." 116 | err "Test it out locally by:" 117 | err "" 118 | err " $ rackup" 119 | err "" 120 | err "You may now use your project as-is in a Rack-compatible environment," 121 | err "such as Pow, Heroku or a host that supports Passenger." 122 | end 123 | 124 | task.description = "Makes a project Rack-compatible." 125 | task.category = :project 126 | 127 | task(:version) do 128 | puts "Proton #{Proton::VERSION}" 129 | end 130 | 131 | task.description = "Shows the current version" 132 | task.category = :misc 133 | 134 | task(:help) do 135 | show_help_for(params.first) and pass if params.any? 136 | 137 | show_task = Proc.new { |name, t| err " %-20s %s" % [ t.usage || name, t.description ] } 138 | 139 | err "Usage: #{executable} " 140 | 141 | unless project? 142 | err "\nCommands:" 143 | tasks_for(:create).each &show_task 144 | end 145 | 146 | if project? 147 | err "\nProject commands:" 148 | tasks_for(:project).each &show_task 149 | end 150 | 151 | if other_tasks.any? 152 | err "\nOthers:" 153 | other_tasks.each &show_task 154 | end 155 | err "\nMisc commands:" 156 | tasks_for(:misc).each &show_task 157 | 158 | unless project? 159 | err 160 | err "Get started by typing:" 161 | err " $ #{executable} create my_project" 162 | end 163 | err 164 | err "Type `#{executable} help COMMAND` for additional help on a command." 165 | end 166 | 167 | task.description = "Shows help for a given command" 168 | task.usage = "help [COMMAND]" 169 | task.category = :misc 170 | 171 | invalid do 172 | task = task(command) 173 | if task 174 | err "Invalid usage." 175 | err "Try: #{executable} #{task.usage}" 176 | err 177 | err "Type `#{executable} help` for more info." 178 | else 179 | err "Invalid command: #{command}" 180 | err "Type `#{executable} help` for more info." 181 | end 182 | end 183 | 184 | def self.run(*argv) 185 | return invoke(:version) if argv == ['-v'] || argv == ['--version'] 186 | trace = (!!argv.delete('--trace')) 187 | 188 | 189 | begin 190 | super *argv 191 | 192 | rescue SyntaxError => e 193 | raise e if trace 194 | err 195 | say_error e.message.split("\n").last 196 | err 197 | say_error "You have a syntax error." 198 | say_info "Use --trace for more info." 199 | 200 | # Convert 'can't load redcloth' to a friendly 'please gem install RedCloth' 201 | rescue LoadError => e 202 | raise e if trace 203 | show_needed_gem gem_name(e) 204 | 205 | # Print generic errors as something friendlier 206 | rescue => e 207 | raise e if trace 208 | 209 | # Can't assume that HAML is always available. 210 | if Object.const_defined?(:Haml) && e.is_a?(Haml::Error) 211 | # Convert HAML's "Can't run XX filter; required 'yy'" messages 212 | # to something friendlier 213 | needed = %w(rdiscount stringio sass/plugin redcloth) 214 | needed.detect { |what| show_needed_gem(what) && true if e.message.include?(what) } 215 | else 216 | err 217 | say_error "#{e.class}: #{e.message}" 218 | say_info "#{e.backtrace.first}" 219 | err 220 | say_error "Oops! An error occured." 221 | say_info "Use --trace for more info." 222 | end 223 | end 224 | end 225 | 226 | def self.find_config_file 227 | Proton::CONFIG_FILES.inject(nil) { |a, fname| a ||= find_in_project(fname) } 228 | end 229 | 230 | def self.run!(options={}) 231 | @config_file = options[:file] || find_config_file 232 | Proton::Project.new rescue nil 233 | super *[] 234 | end 235 | end 236 | end 237 | -------------------------------------------------------------------------------- /lib/proton/cli/helpers.rb: -------------------------------------------------------------------------------- 1 | class Proton 2 | class CLI 3 | module Helpers 4 | def show_help_for(name) 5 | task = task(name) 6 | pass "No such command. Try: #{executable} help" unless task 7 | 8 | help = task.help 9 | if help 10 | help.each { |line| err line } 11 | err 12 | else 13 | err "Usage: #{executable} #{task.usage || name}" 14 | err "#{task.description}." if task.description 15 | end 16 | end 17 | 18 | def tasks_for(category) 19 | tasks.select { |name, t| t.category == category } 20 | end 21 | 22 | def other_tasks 23 | tasks.select { |name, t| t.category.nil? } 24 | end 25 | 26 | def say_info(str) 27 | say_status '*', str, 30 28 | end 29 | 30 | def say_error(str) 31 | say_status 'error', str, 31 32 | end 33 | 34 | def say_status(what, cmd, color=32) 35 | c1 = "\033[0;#{color}m" 36 | c0 = "\033[0;m" 37 | puts "#{c1}%10s#{c0} %s" % [ what, cmd ] 38 | end 39 | 40 | def show_needed_gem(name) 41 | err 42 | say_error "You will need additional gems for this project." 43 | say_info "To install: gem install #{name}" 44 | end 45 | 46 | def no_project 47 | "Error: no Proton config file found.\n" + 48 | "(Looked for #{Proton::CONFIG_FILES.join(', ')})\n\n" + 49 | "You start by creating a config file for this project:\n" + 50 | " $ #{executable} create .\n\n" + 51 | "You may also create an empty project in a new directory:\n" + 52 | " $ #{executable} create NAME\n" 53 | end 54 | 55 | def project? 56 | !! @config_file 57 | end 58 | 59 | # Gets the gem name from a LoadError exception. 60 | def gem_name(e) 61 | name = e.message.split(' ').last 62 | name = 'RedCloth' if name == 'redcloth' 63 | name = 'haml' if name == 'sass/plugin' 64 | name 65 | end 66 | 67 | def project 68 | @project ||= begin 69 | pass no_project unless project? 70 | Dir.chdir File.dirname(@config_file) 71 | 72 | begin 73 | project = Proton.project || Proton::Project.new 74 | pass no_project unless project.config_file 75 | rescue LegacyError 76 | err "This is a legacy Hyde project." 77 | err "To force it, try editing `hyde.conf` and upgrade the version line to `hyde_requirement: 0.1`." 78 | pass 79 | rescue VersionError => e 80 | err e.message 81 | pass 82 | end 83 | 84 | project 85 | end 86 | end 87 | end 88 | end 89 | end 90 | -------------------------------------------------------------------------------- /lib/proton/compass_support.rb: -------------------------------------------------------------------------------- 1 | require 'compass' 2 | 3 | opts = Compass.sass_engine_options 4 | 5 | [:sass, :scss].each do |type| 6 | Proton.project.config.tilt_options(type)[:load_paths] ||= Array.new 7 | Proton.project.config.tilt_options(type)[:load_paths] += opts[:load_paths] 8 | end 9 | -------------------------------------------------------------------------------- /lib/proton/config.rb: -------------------------------------------------------------------------------- 1 | class Proton 2 | # Class: Proton::Config 3 | # Configuration. 4 | # 5 | # ## Common usage 6 | # 7 | # Access it via `Proton.project`. 8 | # 9 | # Proton.project.config 10 | # 11 | # You may access config variables as attributes. 12 | # 13 | # Proton.project.config.site_path 14 | # Proton.project.config.layouts_path 15 | # Proton.project.config.extensions_path 16 | # Proton.project.config.output_path 17 | # 18 | # Tilt options: 19 | # 20 | # Proton.project.config.tilt_options('sass')[:load_path] 21 | # Proton.project.config.tilt_options_for('filename.haml')[:style] 22 | # 23 | class Config 24 | DEFAULTS = { 25 | :site_path => '.', 26 | :layouts_path => '_layouts', 27 | :extensions_path => '_extensions', 28 | :partials_path => '_layouts', 29 | :output_path => '_output', 30 | :tilt_options => { 31 | :haml => { 32 | :escape_html => true 33 | }, 34 | :sass => { 35 | :load_paths => ['css', '.'], 36 | :style => :compact, 37 | :line_numbers => true 38 | }, 39 | :scss => { 40 | :load_paths => ['css', '.'], 41 | :style => :compact, 42 | :line_numbers => true 43 | }, 44 | }, 45 | :tilt_build_options => { 46 | :scss => { 47 | :style => :compressed, 48 | :line_numbers => false 49 | }, 50 | :sass => { 51 | :style => :compressed, 52 | :line_numbers => false 53 | } 54 | } 55 | } 56 | 57 | def self.load(config_file) 58 | new(YAML::load_file(config_file)) rescue new 59 | end 60 | 61 | def initialize(options={}) 62 | # Try to emulate proper .merge behavior in Ruby 1.8 63 | #DEFAULTS.each { |k, v| options[k] ||= v } 64 | @table = Hashie::Mash.new 65 | @table.deep_merge! DEFAULTS 66 | @table.deep_merge! options 67 | end 68 | 69 | # Passthru 70 | def method_missing(meth, *args, &blk) 71 | @table.send meth, *args 72 | end 73 | 74 | def requirement 75 | # Backward compatibility; this config option used to be called 76 | # `hyde_requirement` before the project was renamed to Proton. 77 | self[:requirement] || self[:hyde_requirement] 78 | end 79 | 80 | # Method: tilt_options_for (Proton::Config) 81 | # Returns tilt options for a given file. 82 | # 83 | # ## Usage 84 | # tilt_options_for(filename, options={}) 85 | # 86 | # ## Example 87 | # tilt_options_for('index.haml') # { :escape_html => ... } 88 | # 89 | def tilt_options_for(file, options={}) 90 | ext = file.split('.').last.downcase 91 | opts = tilt_options(ext) || Hash.new 92 | opts = opts.merge(tilt_options(ext, :tilt_build_options)) if options[:build] 93 | 94 | to_hash opts 95 | end 96 | 97 | # Method: tilt_options (Proton::Config) 98 | # Returns tilt options for a given engine. 99 | # 100 | # ## Usage 101 | # tilt_options(engine_name) 102 | # 103 | # ## Example 104 | # tilt_options('haml') # { :escape_html => ... } 105 | # 106 | def tilt_options(what, key=:tilt_options) 107 | @table[key] ||= Hash.new 108 | @table[key][what.to_s] ||= Hash.new 109 | end 110 | 111 | private 112 | def to_hash(mash) 113 | mash.inject(Hash.new) { |h, (k, v)| h[k.to_sym] = v; h } 114 | end 115 | end 116 | end 117 | -------------------------------------------------------------------------------- /lib/proton/helpers.rb: -------------------------------------------------------------------------------- 1 | # Module: Proton::Helpers 2 | # Helpers you can use in your pages. 3 | # 4 | # ## Creating your own helpers 5 | # To create for own helpers, make an extension. See [Extending Proton: 6 | # Helpers][1] for more info. 7 | # 8 | # [1]: /extending/helpers.html 9 | 10 | class Proton 11 | module Helpers 12 | 13 | # Helper: partial (Helpers) 14 | # Renders a partial. 15 | # 16 | # ## Usage 17 | # <%= partial path, locals %> 18 | # 19 | # ## Description 20 | # See [Introduction: Partials](/introduction/partials.html) for more 21 | # info. 22 | # 23 | # ## Example 24 | # 25 | # If your `_layouts/_banner.erb` looks like this: 26 | # 27 | # 30 | # 31 | # ...Then this will embed the partial `_layouts/_nav.erb`. The partial 32 | # will be rendered with `start` being set to the current page. 33 | # 34 | # <%= partial '_banner', :start => page %> 35 | # 36 | def partial(path, locals={}) 37 | partial = Partial[path.to_s, page] or return '' 38 | partial.to_html locals.merge(:page => self) 39 | end 40 | 41 | # Helper: rel (Helpers) 42 | # Turns a path into a relative path. 43 | # 44 | # ## Usage 45 | # <%= rel(path) %> 46 | # 47 | # ## Description 48 | # `rel` takes a given absolute path that begins with a `/` (for instance, 49 | # `/x/y/z.html`) and returns a relative path (maybe `../y/z.html`). This is 50 | # useful if your site will not be be hosted on it's own domain. 51 | # 52 | # ## Example 53 | # <% page.children.each do |child| %> 54 | # 55 | # <%= child.title %> 56 | # 57 | # <% end %> 58 | # 59 | # This may output: 60 | # 61 | # 62 | # Foobar 63 | # 64 | # 65 | # ...where the `../../` depends on the current page's path. 66 | # 67 | def rel(path, from=page.path) 68 | if path[0] == '/' 69 | depth = from.count('/') 70 | dotdot = depth > 1 ? ('../' * (depth-1)) : './' 71 | str = (dotdot[0...-1] + path).squeeze('/') 72 | str = str[2..-1] if str[0..-1] == './' 73 | str 74 | else 75 | path 76 | end 77 | end 78 | 79 | # Helper: content_for (Helpers) 80 | # Content for. 81 | # 82 | # ## See also 83 | # 84 | # * {Helpers:has_content?} 85 | # * {Helpers:content_for} 86 | # * {Helpers:yield_content} 87 | # 88 | def content_for(key, &blk) 89 | content_blocks[key.to_sym] = blk 90 | end 91 | 92 | def content_blocks 93 | $content_blocks ||= Hash.new 94 | $content_blocks[page.path] ||= Hash.new 95 | end 96 | 97 | # Helper: has_content? (Helpers) 98 | # Checks if there's something defined for a given content block. 99 | # 100 | # ## Example 101 | # See {Helpers:content_for} for an example. 102 | # 103 | # ## See also 104 | # * {Helpers:has_content?} 105 | # * {Helpers:content_for} 106 | # * {Helpers:yield_content} 107 | # 108 | def has_content?(key) 109 | content_blocks.member? key.to_sym 110 | end 111 | 112 | # Helper: yield_content (Helpers) 113 | # Yield 114 | # 115 | # ## Example 116 | # See {Helpers:content_for} for an example. 117 | # 118 | # ## See also 119 | # * {Helpers:has_content?} 120 | # * {Helpers:content_for} 121 | # * {Helpers:yield_content} 122 | # 123 | def yield_content(key, *args) 124 | content = content_blocks[key.to_sym] 125 | if respond_to?(:block_is_haml?) && block_is_haml?(content) 126 | capture_haml(*args, &content) 127 | elsif content 128 | content.call(*args) 129 | end 130 | end 131 | end 132 | end 133 | -------------------------------------------------------------------------------- /lib/proton/layout.rb: -------------------------------------------------------------------------------- 1 | class Proton 2 | class Layout < Page 3 | attr_accessor :page 4 | 5 | def self.[](id, page) 6 | object = super(id, page.project) 7 | object.page = page if object 8 | object 9 | end 10 | 11 | protected 12 | def self.root_path(project, *a) 13 | project.path(:layouts, *a) 14 | end 15 | 16 | def default_layout 17 | nil 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /lib/proton/meta.rb: -------------------------------------------------------------------------------- 1 | # Class: Proton::Meta 2 | # Metadata. 3 | # 4 | # This is usually accessed via {Proton::Page.meta}. 5 | 6 | class Proton 7 | class Meta < OpenStruct 8 | def merge!(hash) 9 | @table.merge(hash) 10 | end 11 | 12 | # For Ruby 1.8.6 compatibility ([:type] instead of .type) 13 | def [](id) 14 | @table[id.to_sym] 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/proton/page.rb: -------------------------------------------------------------------------------- 1 | class Proton 2 | # Class: Proton::Page 3 | # A page. 4 | # 5 | # ## Common usage 6 | # 7 | # Getting pages from paths: 8 | # 9 | # # Feed it a URL path, not a filename. 10 | # page = Proton::Page['/index.html'] # uses Proton.project 11 | # page = Proton::Page['/index.html', project] 12 | # 13 | # Getting pages from files: 14 | # 15 | # # Feed it a file name, not a URL path. 16 | # # Also, this does no sanity checks. 17 | # page = Proton::Page.new('/home/rsc/index.html', project) 18 | # 19 | # page.exists? 20 | # page.valid? 21 | # 22 | # Paths: 23 | # 24 | # page.filepath #=> "index.haml" -- path in the filesystem 25 | # page.path #=> "/index.html" -- path as a RUL 26 | # 27 | # Meta: 28 | # 29 | # page.meta #=> OpenStruct of the metadata 30 | # page.title #=> "Welcome to my site!" 31 | # 32 | # page.layout # Proton::Layout or nil 33 | # page.layout? 34 | # 35 | # Types: 36 | # 37 | # page.html? 38 | # page.mime_type #=> "text/html" or nil -- only for tilt? == true 39 | # page.default_ext #=> "html" 40 | # 41 | # Contents: 42 | # 43 | # page.to_html 44 | # page.to_html(locals={}) 45 | # page.content 46 | # page.markup 47 | # 48 | # Traversion: 49 | # 50 | # 51 | # # Pages (a Proton::Page or nil) 52 | # page.parent 53 | # page.next 54 | # 55 | # # Sets (a Proton::Set) 56 | # page.children 57 | # page.siblings 58 | # page.breadcrumbs 59 | # 60 | # # Misc 61 | # page.index? # if it's an index.html 62 | # page.parent? 63 | # page.root? # true if no parents 64 | # page.depth 65 | # 66 | # Tilt: 67 | # 68 | # page.tilt? # true, if it's a dynamic file 69 | # page.tilt_engine_name #=> 'RedCloth' 70 | # 71 | # Building: 72 | # 73 | # page.write 74 | # page.write('~/foo.html') 75 | # 76 | class Page 77 | # Attribute: project (Proton::Page) 78 | # A reference to the project. 79 | # 80 | attr_reader :project 81 | 82 | # Attribute: file (Proton::Page) 83 | # The full path of the source file. 84 | # 85 | # ## Example 86 | # page.filepath #=> "/index.haml" 87 | # page.file #=> "/home/rsc/project/index.haml" 88 | # 89 | # ## See also 90 | # - {Proton::Page.filepath} 91 | # 92 | attr_reader :file 93 | 94 | def self.[](id, project=Proton.project) 95 | Cacheable.cache(:lookup, id, project.root) do 96 | site_path = root_path(project) 97 | return nil if site_path.nil? 98 | 99 | site = lambda { |*x| File.join site_path, *(x.compact) } 100 | try = lambda { |_id| p = new(_id, project); p if p.exists? } 101 | 102 | # For paths like '/' or '/hello/' 103 | nonfile = File.basename(id).gsub('/','').empty? 104 | 105 | # Account for: 106 | # ~/mysite/site/about/us.html.haml 107 | # about/us.html.haml => ~/mysite/site/about/us.html.haml 108 | # about/us.html => ~/mysite/site/about/us.html.* 109 | # about/us.html => ~/mysite/site/about/us.* 110 | # about/us => ~/mysite/site/about/us/index.* 111 | # 112 | page = try[id] 113 | page ||= try[site[id]] 114 | unless nonfile 115 | page ||= try[Dir[site["#{id}.*"]].first] 116 | page ||= try[Dir[site["#{id.to_s.sub(/\.[^\.]*/,'')}.*"]].first] 117 | end 118 | page ||= try[Dir[site[id, "index.*"]].first] 119 | 120 | # Subclass 121 | if page && page.tilt? && page.meta[:type] 122 | klass = Page.get_type(page.meta[:type]) 123 | raise Error, "#{page.filepath}: Class for type '#{page.meta[:type]}' not found" unless klass 124 | page = klass.new(id, project) 125 | end 126 | 127 | page 128 | end 129 | end 130 | 131 | def initialize(file, project=Proton.project) 132 | @file = File.expand_path(file) if file.is_a?(String) 133 | @project = project 134 | raise Error if project.nil? 135 | end 136 | 137 | # Returns the URL path for a page. 138 | def path 139 | path = @file.sub(File.expand_path(root_path), '') 140 | 141 | # if xx.haml (but not xx.html.haml), 142 | if tilt? 143 | path = path.sub(/\.[^\.]*$/, "") 144 | path += ".#{default_ext}" unless File.basename(path).include?('.') 145 | end 146 | 147 | path 148 | end 149 | 150 | # Attribute: filepath (Proton::Page) 151 | # Returns a short filepath relative to the project path. 152 | # 153 | # ## Description 154 | # This is different from {Proton::Page.file} as this only returns the 155 | # path relative to the project's root instead of an absolute path. 156 | # 157 | # ## Example 158 | # See {Proton::Page.file} for an example. 159 | # 160 | def filepath 161 | root = project.root 162 | fpath = file 163 | fpath = fpath[root.size..-1] if fpath[0...root.size] == root 164 | fpath 165 | end 166 | 167 | # Attribute: title (Proton::Page) 168 | # Returns the page title as a string. 169 | # 170 | # ## Description 171 | # This attribute tries to infer the page's title based on metadata. If the 172 | # `title` key is not in the page's header metadata, then it returns the 173 | # path name instead. 174 | # 175 | # This is also aliased as `to_s`. 176 | # 177 | def title 178 | (meta.title if tilt?) || path 179 | end 180 | 181 | alias to_s title 182 | 183 | def position 184 | meta[:position] || title 185 | end 186 | 187 | def <=>(other) 188 | result = self.position <=> other.position 189 | result ||= self.position.to_s <=> other.position.to_s 190 | result 191 | end 192 | 193 | # Method: html? (Proton::Page) 194 | # Returns true if the page is an HTML page. 195 | 196 | def html? 197 | mime_type == 'text/html' 198 | end 199 | 200 | # Attribute: mime_type (Proton::Page) 201 | # The MIME type for the page, based on what template engine was used. 202 | # 203 | # ## Example 204 | # Page['/style.css'].mime_type #=> 'text/css' 205 | # Page['/index.html'].mime_type #=> 'text/html' 206 | # 207 | # ## See also 208 | # - {Proton::Page::default_ext} 209 | # 210 | def mime_type 211 | return nil unless tilt? 212 | 213 | mime = nil 214 | mime = tilt_engine.default_mime_type if tilt_engine.respond_to?(:default_mime_type) 215 | 216 | mime ||= case tilt_engine.name 217 | when 'Tilt::SassTemplate' then 'text/css' 218 | when 'Tilt::ScssTemplate' then 'text/css' 219 | when 'Tilt::LessTemplate' then 'text/css' 220 | when 'Tilt::CoffeeScriptTemplate' then 'application/javascript' 221 | when 'Tilt::NokogiriTemplate' then 'text/xml' 222 | when 'Tilt::BuilderTemplate' then 'text/xml' 223 | else 'text/html' 224 | end 225 | end 226 | 227 | # Attribute: default_ext (Proton::Page) 228 | # Returns a default extension for the page based on the page's MIME type. 229 | # 230 | # ## Example 231 | # Page['/style.css'].default_ext #=> 'css' 232 | # Page['/index.html'].default_ext #=> 'html' 233 | # 234 | # ## See also 235 | # - {Proton::Page::mime_type} 236 | 237 | def default_ext 238 | case mime_type 239 | when 'text/html' then 'html' 240 | when 'text/css' then 'css' 241 | when 'text/xml' then 'xml' 242 | when 'application/javascript' then 'js' 243 | end 244 | end 245 | 246 | # Method: get_type (Proton::Page) 247 | # Returns a page subtype. 248 | # 249 | # ## Example 250 | # Page.get_type('post') => Proton::Page::Post 251 | 252 | def self.get_type(type) 253 | type = type.to_s 254 | klass = type[0..0].upcase + type[1..-1].downcase 255 | klass = klass.to_sym 256 | self.const_get(klass) if self.const_defined?(klass) 257 | end 258 | 259 | def exists? 260 | @file and File.file?(@file||'') and valid? 261 | end 262 | 263 | # Ensures that the page is in the right folder. 264 | def valid? 265 | prefix = File.expand_path(root_path) 266 | prefix == File.expand_path(@file)[0...prefix.size] 267 | end 268 | 269 | def content(locals={}, tilt_options={}, &blk) 270 | return markup unless tilt? 271 | tilt(tilt_options).render(dup.extend(Helpers), locals, &blk) 272 | end 273 | 274 | # Method: to_html (Proton::Page) 275 | # Returns the full HTML document for the page. 276 | # 277 | def to_html(locals={}, tilt_options={}, &blk) 278 | html = content(locals, tilt_options, &blk) 279 | html = layout.to_html(locals, tilt_options) { html } if layout? 280 | html 281 | end 282 | 283 | def layout 284 | layout = meta.layout 285 | layout ||= default_layout unless meta.layout == false 286 | Layout[layout, page] if layout 287 | end 288 | 289 | def page 290 | self 291 | end 292 | 293 | def layout? 294 | !! layout 295 | end 296 | 297 | # Method: meta (Proton::Page) 298 | # Returns the metadata for the page. 299 | # 300 | # ## Description 301 | # This returns an instance of {Proton::Meta}. 302 | # 303 | def meta 304 | @meta ||= Meta.new(parts.first) 305 | end 306 | 307 | # Method: write (Proton::Page) 308 | # Writes to the given output file. 309 | # 310 | # ## Description 311 | # This is the method used by `proton build`. 312 | # 313 | def write(out=nil) 314 | out ||= project.path(:output, path) 315 | FileUtils.mkdir_p File.dirname(out) 316 | 317 | if tilt? 318 | File.open(out, 'w') { |f| f.write to_html({}, :build => true) } 319 | else 320 | FileUtils.cp file, out 321 | end 322 | end 323 | 324 | # Method: tilt? (Proton::Page) 325 | # Checks if the file is supported by tilt. 326 | # 327 | def tilt? 328 | !! tilt_engine 329 | end 330 | 331 | # Attribute: tilt_engine (Proton::Page) 332 | # Returns the Tilt engine (eg Tilt::HamlEngine). 333 | def tilt_engine 334 | Tilt[@file] 335 | end 336 | 337 | def tilt_engine_name 338 | tilt_engine.name.match(/:([^:]*)(?:Template?)$/)[1] 339 | end 340 | 341 | # Attribute: tilt (Proton::Page) 342 | # Returns the tilt layout. 343 | # 344 | # This returns an instance of `Tilt`. 345 | # 346 | def tilt(tilt_options={}) 347 | if tilt? 348 | parts 349 | # HAML options and such (like :escape_html) 350 | options = project.config.tilt_options_for(@file, tilt_options) 351 | offset = @offset || 1 352 | Tilt.new(@file, offset, options) { markup } 353 | end 354 | end 355 | 356 | def markup 357 | parts.last 358 | end 359 | 360 | def method_missing(meth, *args, &blk) 361 | super unless meta.instance_variable_get(:@table).keys.include?(meth.to_sym) 362 | meta.send(meth) 363 | end 364 | 365 | # Attribute: parent (Proton::Page) 366 | # Returns the page's parent page, or nil. 367 | # 368 | # ## Usage 369 | # page.parent 370 | # 371 | # ## Description 372 | # This will return the page's parent (also a {Proton::Page} instance), or 373 | # `nil` if it's the page is already the root. 374 | # 375 | def parent 376 | parts = path.split('/') # ['', 'about', 'index.html'] 377 | 378 | try = lambda { |newpath| p = self.class[newpath, project]; p if p && p.path != path } 379 | 380 | # Absolute root 381 | return nil if index? and parts.size <= 2 382 | 383 | parent = try[parts[0...-1].join('/')] # ['','about'] => '/about' 384 | parent ||= try['/'] # Home 385 | end 386 | 387 | # Method: children (Proton::Page) 388 | # Returns a Set of the page's subpages. 389 | # 390 | def children 391 | files = if index? 392 | # about/index.html => about/* 393 | File.expand_path('../*', @file) 394 | else 395 | # products.html => products/* 396 | base = File.basename(@file, '.*') 397 | File.expand_path("../#{base}/*", @file) 398 | end 399 | 400 | Set.new Dir[files]. 401 | reject { |f| f == @file || project.ignored_files.include?(f) }. 402 | map { |f| self.class[f, project] }. 403 | compact.sort 404 | end 405 | 406 | # Method: siblings (Proton::Page) 407 | # Returns a Set of pages that share the same parent as the current page. 408 | # 409 | def siblings 410 | pages = (p = parent and p.children) 411 | return Set.new unless pages 412 | return Set.new unless pages.include?(self) 413 | Set.new(pages) 414 | end 415 | 416 | # Attribute: breadcrumbs (Proton::Page) 417 | # Returns an array of the page's ancestors, including itself. 418 | # 419 | # ## Example 420 | # Proton::Page['/about/company/contact.html'].breadcrumbs 421 | # 422 | # May look like: 423 | # [ Page, Page, Page ] 424 | # 425 | def breadcrumbs 426 | Set.new(parent? ? (parent.breadcrumbs + [self]) : [self]) 427 | end 428 | 429 | # Method: index? (Proton::Page) 430 | # Returns true if the page is and index page. 431 | # 432 | def index? 433 | File.basename(path, '.*') == 'index' 434 | end 435 | 436 | # Method: parent? (Proton::Page) 437 | # Returns true if the page has a parent. 438 | # 439 | # ## Description 440 | # This is the opposite of {Proton::Page::root?}. 441 | # 442 | # ## See also 443 | # - {Proton::Page::root?} 444 | 445 | def parent? 446 | !parent.nil? 447 | end 448 | 449 | # Method: root? (Proton::Page) 450 | # Returns true if the page is the home page. 451 | # 452 | # ## Description 453 | # This is the opposite of {Proton::Page::parent?}. 454 | # 455 | # ## See also 456 | # - {Proton::Page::parent?} 457 | 458 | def root? 459 | parent.nil? 460 | end 461 | 462 | # Attribute: depth (Proton::Page) 463 | # Returns how deep the page is in the heirarchy. 464 | # 465 | # ## Description 466 | # This counts the number of pages from the root page. This means: 467 | # 468 | # * The root page (eg, `/index.html`) has a depth of `1` 469 | # * A child page of the root (eg, `/about.html`) has a depth of `2` 470 | # * A child of that (eg, `/about/company.html`) has a depth of `3` 471 | # * ...and so on 472 | # 473 | # 474 | def depth 475 | breadcrumbs.size 476 | end 477 | 478 | def next 479 | page = self 480 | while true do 481 | page.siblings.index(self) 482 | end 483 | end 484 | 485 | def ==(other) 486 | self.path == other.path 487 | end 488 | 489 | def inspect 490 | "<##{self.class.name} #{path.inspect}>" 491 | end 492 | 493 | protected 494 | 495 | # Method: default_layout (Proton::Page) 496 | # Returns the default layout. 497 | # 498 | # This method may be overridden by subclasses as needed. 499 | 500 | def default_layout 501 | 'default' if html? 502 | end 503 | 504 | # Returns the two parts of the markup. 505 | def parts 506 | @parts ||= begin 507 | t = File.open(@file).read 508 | t = t.force_encoding('UTF-8') if t.respond_to?(:force_encoding) 509 | m = t.match(/^(.*?)\n--+\n(.*)$/m) 510 | 511 | if m.nil? 512 | [{}, t] 513 | else 514 | @offset = m[1].count("\n") + 2 515 | data = YAML::load(m[1]) 516 | raise ArgumentError unless data.is_a?(Hash) 517 | [data, m[2]] 518 | end 519 | rescue ArgumentError 520 | [{}, t] 521 | end 522 | end 523 | 524 | extend Cacheable 525 | cache_method :children, :siblings, :parent, :next, :breadcrumbs, :path, :tilt 526 | 527 | def self.root_path(project, *a) 528 | project.path(:site, *a) 529 | end 530 | 531 | def root_path(*a) 532 | self.class.root_path(project, *a) 533 | end 534 | end 535 | end 536 | -------------------------------------------------------------------------------- /lib/proton/partial.rb: -------------------------------------------------------------------------------- 1 | class Proton 2 | class Partial < Layout 3 | protected 4 | def self.root_path(project, *a) 5 | project.path(:partials, *a) 6 | end 7 | 8 | def default_layout 9 | nil 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/proton/project.rb: -------------------------------------------------------------------------------- 1 | class Proton 2 | # Class: Proton::Project 3 | # A project. 4 | # 5 | # ## Common usage 6 | # 7 | # Instanciating: 8 | # 9 | # project = Project.new('~/spur') 10 | # project == Proton.project # the last defined project 11 | # 12 | # Building: 13 | # 14 | # project.build 15 | # project.build { |file| puts "Building #{file}..." } 16 | # 17 | # Getting pages: 18 | # 19 | # Proton::Page['/index.html'] # ~/spur/index.md; uses Proton.project 20 | # 21 | # Configuration: 22 | # 23 | # project.config_file # ~/spur/hyde.conf 24 | # project.config # Config from above file (OpenStruct) 25 | # project.config.site_path 26 | # 27 | # Paths: 28 | # 29 | # project.path(:site) # ~/spur/site (based on config site_path) 30 | # project.path(:extensions) 31 | # 32 | # project.root('a/b', 'c') # ~/spur/a/b/c 33 | # 34 | # Indexing: 35 | # 36 | # project.pages # [<#Page>, <#Page>, ...] 37 | # project.files # ['/index.md', '/style.sass', ...] 38 | # # (only site files) 39 | # project.ignored_files 40 | # 41 | class Project 42 | def initialize(root=Dir.pwd) 43 | @root = root 44 | Proton.project = self 45 | 46 | validate_version 47 | load_extensions 48 | 49 | load File.expand_path('../compass_support.rb', __FILE__) 50 | end 51 | 52 | def validate_version 53 | return unless config_file? 54 | req = config.requirement.to_s 55 | 56 | v = lambda { |version| Gem::Version.new version } 57 | 58 | if req.empty? 59 | # pass 60 | elsif v[req] < v["0.1"] 61 | raise LegacyError, "This is a legacy project" 62 | elsif v[req] > v[Proton.version] 63 | raise VersionError, "You will need Proton version >= #{req} for this project." 64 | end 65 | end 66 | 67 | def load_extensions 68 | path = path(:extensions) 69 | 70 | ( Dir[path(:extensions, '*.rb')] + 71 | Dir[path(:extensions, '*', '*.rb')] 72 | ).sort.each { |f| require f } if path 73 | end 74 | 75 | # Method: config_file (Proton::Project) 76 | # Returns the configuration file for the project. 77 | 78 | def config_file 79 | try = lambda { |path| p = root(path); p if File.file?(p) } 80 | Proton::CONFIG_FILES.inject(nil) { |acc, file| acc ||= try[file] } 81 | end 82 | 83 | def config_file? 84 | config_file 85 | end 86 | 87 | # Method: config (Proton::Project) 88 | # Returns a Proton::Config instance. 89 | 90 | def config 91 | @config ||= Config.load(config_file) 92 | end 93 | 94 | # Method: path (Proton::Project) 95 | # Returns the path for a certain aspect. 96 | # 97 | # ## Example 98 | # 99 | # Proton.project.path(:site) 100 | 101 | def path(what, *a) 102 | return nil unless [:output, :site, :layouts, :extensions, :partials].include?(what) 103 | path = config.send(:"#{what}_path") 104 | root path, *a if path 105 | end 106 | 107 | # Method: root (Proton::Project) 108 | # Returns the root path of the project. 109 | 110 | def root(*args) 111 | File.join @root, *(args.compact) 112 | end 113 | 114 | # Method: pages (Proton::Project) 115 | # Returns the pages for the project. 116 | 117 | def pages 118 | files.map { |f| Page[f, self] }.compact 119 | end 120 | 121 | # Method: files (Proton::Project) 122 | # Returns the site files for the project, free from the ignored files. 123 | 124 | def files 125 | files = Dir[File.join(path(:site), '**', '*')] 126 | files = files.select { |f| File.file?(f) } 127 | files = files.map { |f| File.expand_path(f) } 128 | files - ignored_files 129 | end 130 | 131 | # Method: ignored_files (Proton::Project) 132 | # Returns the files to be ignored for the project. 133 | 134 | def ignored_files 135 | specs = [*config.ignore].map { |s| root(s) } 136 | specs << config_file 137 | 138 | # Ignore the standard files 139 | [:layouts, :extensions, :partials, :output].each do |aspect| 140 | specs << File.join(config.send(:"#{aspect}_path"), '**/*') if path(aspect) && path(aspect) != path(:site) 141 | end 142 | 143 | # Ignore dotfiles and hyde.conf files by default 144 | specs += %w[.* _* *~ README* /config.ru Gemfile Gemfile.lock] 145 | specs += Proton::CONFIG_FILES.map { |s| "/#{s}" } 146 | 147 | specs.compact.map { |s| glob(s) }.flatten.uniq 148 | end 149 | 150 | # Method: build (Proton::Project) 151 | # Builds. 152 | 153 | def build(&blk) 154 | pages.each do |page| 155 | yield page 156 | page.write 157 | end 158 | ensure 159 | build_cleanup 160 | end 161 | 162 | protected 163 | def glob(str) 164 | if str[0] == '/' 165 | Dir[str] + Dir[root(str)] + Dir["#{root(str)}/**"] 166 | else 167 | Dir[root("**/#{str}")] + Dir[root("**/#{str}/**")] 168 | end 169 | end 170 | 171 | def build_cleanup 172 | FileUtils.rm_rf '.sass_cache' 173 | end 174 | end 175 | end 176 | 177 | -------------------------------------------------------------------------------- /lib/proton/server.rb: -------------------------------------------------------------------------------- 1 | require 'cuba' 2 | require 'rack' 3 | require 'proton' 4 | 5 | # The only time this file gets loaded is if you require it explicity, ie, 6 | # in a config.ru. Disable caching for when it's ran as a development-time 7 | # server. 8 | Proton::Cacheable.disable! 9 | 10 | # Module: Proton::Server 11 | # The Proton server rack application. 12 | 13 | class Proton 14 | Server = Cuba.dup 15 | 16 | module Server; end 17 | 18 | module Server::PageHelpers 19 | def not_found 20 | show_status nil 21 | res.status = 404 22 | res.write "

File Not Found

The path #{env['PATH_INFO']} was not found." + " "*1024 23 | end 24 | 25 | def options 26 | @options ||= Hash.new 27 | end 28 | 29 | def show_status(page) 30 | return if options[:quiet] 31 | path = env['PATH_INFO'] 32 | return if path == '/favicon.ico' 33 | 34 | status = page ? "\033[0;32m[ OK ]" : "\033[0;31m[404 ]" 35 | verb = get ? 'GET ' : (post ? 'POST' : '') 36 | puts "%s\033[0;m %s %s" % [ status, verb, env['PATH_INFO'] ] 37 | puts " src: #{page.filepath} (#{page.tilt_engine_name})" if page && page.tilt? 38 | end 39 | 40 | def mime_type_for(page) 41 | type = page.mime_type 42 | type ||= Rack::Mime::MIME_TYPES[File.extname(page.file)] 43 | type 44 | end 45 | 46 | def server 47 | Proton::Server 48 | end 49 | end 50 | 51 | module Proton::Server 52 | Ron.send :include, PageHelpers 53 | 54 | define do 55 | on default do 56 | begin 57 | page = Proton::Page[env['PATH_INFO']] or break not_found 58 | 59 | # Make the clients use If-Modified-Since 60 | res['Cache-Control'] = 'max-age=86400, public, must-revalidate' 61 | 62 | mtime = [server.options[:last_modified].to_i, File.mtime(page.file).to_i].compact.max 63 | res['Last-Modified'] = mtime.to_s if mtime 64 | 65 | # Get the MIME type from Proton, then fallback to Rack 66 | type = mime_type_for(page) 67 | res['Content-Type'] = type if type 68 | 69 | # Okay, we're done 70 | res.write page.to_html 71 | show_status page 72 | rescue => e 73 | res['Content-Type'] = 'text/html' 74 | res.write "

#{e.class}: #{e.message}

" 75 | end 76 | end 77 | end 78 | end 79 | end 80 | 81 | module Proton::Server 82 | # Available options: 83 | # :last_modified -- timestamp for all files 84 | def self.options 85 | @options ||= Hash.new 86 | end 87 | 88 | # :Host, :Port 89 | def self.run!(options={}) 90 | self.options.merge options 91 | handler = rack_handler or return false 92 | handler.run self, options 93 | end 94 | 95 | def self.rack_handler 96 | %w(thin mongrel webrick).each do |svr| 97 | begin 98 | return Rack::Handler.get(svr) 99 | rescue LoadError 100 | rescue NameError 101 | end 102 | end 103 | end 104 | end 105 | -------------------------------------------------------------------------------- /lib/proton/set.rb: -------------------------------------------------------------------------------- 1 | # Class: Proton::Set 2 | # A set of pages. 3 | 4 | class Proton 5 | class Set < Array 6 | # Method: find (Proton::Set) 7 | # Filters a set by given metadata criteria. 8 | # 9 | # ## Example 10 | # Page['/'].children.find(layout: 'default') 11 | # 12 | def find(by={}) 13 | self.class.new(select do |page| 14 | by.inject(true) { |b, (field, value)| b &&= (page.meta.send(field) == value) } 15 | end) 16 | end 17 | 18 | # Method: except (Proton::Set) 19 | # Filters a set by removing items matching the given metadata criteria. 20 | # 21 | # This is the opposite of {Proton::Set::find}. 22 | # 23 | # ## Example 24 | # Page['/'].children.find(layout: 'default') 25 | # 26 | def except(by={}) 27 | self.class.new(reject do |page| 28 | by.inject(true) { |b, (field, value)| b &&= (page.meta.send(field) == value) } 29 | end) 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /lib/proton/version.rb: -------------------------------------------------------------------------------- 1 | class Proton 2 | VERSION = "0.3.4" 3 | 4 | # Attribute: version (Proton) 5 | # Returns the version. 6 | # 7 | # ## Example 8 | # Proton.version #=> "0.2.0" 9 | 10 | def self.version 11 | VERSION 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /manual/config.ru: -------------------------------------------------------------------------------- 1 | gem 'proscribe', '~> 0.0.1' 2 | require 'proscribe' 3 | run ProScribe.rack_app 4 | -------------------------------------------------------------------------------- /manual/contents.haml: -------------------------------------------------------------------------------- 1 | title: Index 2 | position: 9999 3 | -- 4 | %section.index 5 | %ul 6 | != partial '_nav', from: page, p: Proton::Page['/'], level: 1 7 | -------------------------------------------------------------------------------- /manual/extending.md: -------------------------------------------------------------------------------- 1 | title: Extending Proton 2 | position: 2 3 | page_type: section 4 | -- 5 | -------------------------------------------------------------------------------- /manual/extending/adding_commands.md: -------------------------------------------------------------------------------- 1 | title: Adding commands 2 | -- 3 | Proton uses the [Shake](http://github.com/rstacruz/shake) gem. Add tasks to 4 | Proton::CLI as you normally would in Shake. 5 | 6 | [extensions/clean/clean.rb (rb)] 7 | class Proton::CLI 8 | task :clean do 9 | wrong_usage if params.any? 10 | 11 | puts "Cleaning..." 12 | # Do stuff here 13 | puts "All clean!" 14 | end 15 | end 16 | 17 | This may now be used in the command line. 18 | 19 | $ proton clean all 20 | Invalid usage. 21 | Type `proton help clean` for more information. 22 | 23 | $ proton clean 24 | Cleaning... 25 | All done! 26 | 27 | $ proton --help 28 | Usage: proton arguments 29 | 30 | Commands: 31 | .... 32 | clean Cleans up your project's dirt 33 | -------------------------------------------------------------------------------- /manual/extending/creating_extensions.md: -------------------------------------------------------------------------------- 1 | title: Creating extensions 2 | -- 3 | In your project's extensions folder (`extensions` by default), create a file called 4 | `/.rb`, where `` is the name of your extension. This file will automatically loaded. 5 | 6 | Example: 7 | 8 | [extensions/blog/blog.rb (rb)] 9 | class Proton 10 | # Set up autoload hooks for the other classes 11 | prefix = File.dirname(__FILE__) 12 | autoload :Blog, "#{prefix}/lib/blog.rb" 13 | end 14 | 15 | -------------------------------------------------------------------------------- /manual/helpers.md: -------------------------------------------------------------------------------- 1 | title: Helpers 2 | page_type: section 3 | -- 4 | Proton comes with helpers that you can use in your projects. 5 | 6 | To add your own helpers: 7 | 8 | * Create a Ruby file in the `_extensions` folder. 9 | * Add new methods to the module [Proton::Helpers](proton/helpers.html). 10 | 11 | Any methods here will be available to your pages and templates. 12 | 13 | ## Example 14 | 15 | In this example, we'll create a simple helper function. 16 | 17 | [_extensions/helpers.rb (rb)] 18 | class Proton 19 | module Helpers 20 | def form_tag(meth, action, &b) 21 | [ "
", 22 | b.call, 23 | "
" 24 | ].join("\n") 25 | end 26 | end 27 | end 28 | 29 | In your project's site files, you can then now use this helper. 30 | 31 | [my_page.haml (haml)] 32 | %h1 My form 33 | != form_tag 'post', '/note/new' do 34 | %p 35 | %label Your name: 36 | %input{ :type => 'text', :name => 'name' } 37 | %p 38 | %label Your email: 39 | %input{ :type => 'text', :name => 'email' } 40 | 41 | -------------------------------------------------------------------------------- /manual/index.textile: -------------------------------------------------------------------------------- 1 | title: Proton manual 2 | brief: Proton is a website preprocessor. 3 | -- 4 | 5 |
 6 | $ gem install proton
 7 | $ proton
 8 | 
9 | 10 | h2. Why use Proton? 11 | 12 | It's like building a static site, but better! You can use Proton for: 13 | 14 | * Building HTML prototypes 15 | * Building sites with no dynamic logic 16 | * Creating a blog where the entries are stored in a source repository 17 | 18 | h2. Getting started 19 | 20 |
21 |
22 | $ proton create myproject
23 |   create   myproject/
24 |   create   myproject/index.md
25 |   create   myproject/Protonfile
26 |   ...
27 | 
28 | $ cd myproject
29 | 
30 | 31 | h4. Create your first project 32 | 33 | Create your first project using "@proton create@":proton_create.html. This will create a new folder for you. 34 |
35 | 36 |
37 |
38 | $ proton start
39 | * Starting server...
40 | >> Thin web server (v1.2.11 codename Bat-Shit Crazy)
41 | >> Maximum connections set to 1024
42 | >> Listening on 0.0.0.0:4833, CTRL+C to stop
43 | 
44 | 45 | h4. Open a live preview 46 | 47 | Typing "@proton start@":proton_start.html, will get you a live preview in `http://localhost:4833`. Point your browser there to see your changes as you make them. 48 |
49 | 50 |
51 |
52 | [myproject/index.haml (haml)]
53 | %h1 Helol teher!
54 | %p Welcome nt omy site.
55 | 
56 | 57 |
58 | [myproject/about_us.markdown (markdown)]
59 | About us
60 | ========
61 | 
62 | This is text written in Markdown.
63 | 
64 | 65 | h4. Edit your pages 66 | 67 | Use your favorite text editor to edit your files. You can write in Markdown, Textile or "HAML":http://hamllang.com for HTML, or "Sass":http://sass-lang.com for CSS, and many more. 68 |
69 | 70 |
71 |
72 | $ proton build
73 |        * _output/index.html
74 |        * _output/about_us.html
75 | 
76 | 77 | h4. Build your HTML 78 | 79 | By typing "@proton build@":proton_build.html, you get your site as simple HTML files. 80 |
81 | 82 | h2. Features 83 | 84 | * __Layouts and Partials:__ Proton lets you define your site's header and footer layouts in a separate file, and even separate snippets of your site into reuseable components (partials). Your code will be much cleaner and DRYer! 85 | 86 | * __Template languages:__ Proton lets you write your site in any template language you need -- the translation will be taken care of for you. Proton supports HAML, LessCSS, Markdown, SASS and Textile by default, and more can be added through extensions. 87 | 88 | * __Extendable:__ Proton is easily customizable with extensions. You can add new helpers, new commands, support for new languages and many more by simply adding the extensions to your project folder. 89 | 90 | * __Design fast:__ Proton comes with a web server that lets you serve up your site locally. Any changes to your files will be seen on your next browser refresh! 91 | 92 | * __Build your site as static HTMLs:__ You can export your site as plain HTML files with one simple command. 93 | 94 | Source 95 | -------------------------------------------------------------------------------- /manual/introduction.md: -------------------------------------------------------------------------------- 1 | title: Introduction 2 | position: 1 3 | page_type: section 4 | -- 5 | -------------------------------------------------------------------------------- /manual/introduction/config.md: -------------------------------------------------------------------------------- 1 | title: Configuration 2 | -- 3 | 4 | Configuration is done through the file `Protonfile` placed in your project's 5 | root folder. A sample config file is generated 6 | when doing `proton create`. 7 | 8 | It is a YAML file, so the basic format of the file is: 9 | 10 | [Protonfile (yaml)] 11 | option: value 12 | # Lines starting with # are comments that are ignored. 13 | 14 | ### requirement 15 | 16 | The minimum version of Proton needed by the project. Example: 17 | 18 | [Protonfile (yaml)] 19 | requirement: 0.0.5 20 | 21 | ### site_path 22 | The folder where the site's main files are kept. (you can set this to '.') 23 | This is the path where your main files are. Example: 24 | 25 | [myproject/Protonfile (yaml)] 26 | # This will instruct Proton to look at myproject/site/ for the 27 | # files of the project. 28 | 29 | site_path: site/ 30 | 31 | 32 | ### layouts_path 33 | The folder where the layout templates (and partials) are kept. See the 34 | [Layouts](layouts.html) section for information on Proton layouts. 35 | 36 | ### partials_path 37 | The folder for partials. See the [Partials](partials.html) section for 38 | an overview of what partials are. 39 | 40 | ### extensions_path 41 | The folder where the optional extensions are kept. See the 42 | [Extending Proton](extending.html) section for more info on extensions. 43 | 44 | ### output_path 45 | The folder where the HTML files are to be built when typing `proton build`. 46 | 47 | More options 48 | ------------ 49 | 50 | These options are not in the default `Protonfile`, but you may simply 51 | add them in. 52 | 53 | ### port 54 | The port number. Defaults to 4833 unless set. Example: 55 | 56 | [Protonfile (yaml)] 57 | port: 4999 58 | 59 | ### gems 60 | This is a list of Ruby gems to be autoloaded into Proton. Some extensions 61 | are available as gems and may simply be added here to be used. Example: 62 | 63 | [Protonfile (yaml)] 64 | gems: 65 | - proton-rst 66 | - proton-zip 67 | 68 | Hidden Proton config file 69 | ------------------------- 70 | 71 | Don't like seeing `Protonfile` littering up your project folder? Rename 72 | it to `.protonrc`. 73 | 74 | -------------------------------------------------------------------------------- /manual/introduction/getting_started.md: -------------------------------------------------------------------------------- 1 | title: Getting started 2 | position: 2 3 | -- 4 | 5 | Starting your first project 6 | --------------------------- 7 | 8 | Create your first project with: 9 | 10 | $ proton create 11 | 12 | Where `` is the name of your project. This will create a folder with that 13 | name, along with some sample files to get you started. 14 | 15 | Starting 16 | -------- 17 | 18 | Begin working on your project by starting the Proton webserver. This is 19 | optional, but is recommended as it's a nice way to see your changes in real 20 | time. 21 | 22 | $ proton start 23 | 24 | After typing this, you will see the server has started. Point your web browser to 25 | `http://localhost:4833` to see your site. You should now see your project's 26 | default "welcome" page. 27 | 28 | 29 | Editing your site 30 | ----------------- 31 | 32 | Your project has a subfolder called `site` -- this is where all the site's files are 33 | stored. In general, dropping any file in this folder will make it accessible with the 34 | same filename. 35 | 36 | Try this: create a file called `products.html` and fill it up like you would an 37 | HTML page. After that, point your browser to `http://localhost:4833/products.html`, 38 | which should now show the page you were working on. 39 | 40 | You may also put your files in subfolders. If you were to create the file 41 | `site/assets/my_style.css`, it should be accessible through 42 | `http://localhost:4833/assets/my_style.css`. 43 | 44 | Dynamic files 45 | ------------- 46 | 47 | Proton supports many templating languages like HAML, Less, and ERB (more on this later). 48 | If your file ends in one of these supported extensions (e.g., `index.haml`), it 49 | is assumed to be a dynamic file and will be rendered by it's corresponding templating 50 | engine (in this case, HAML). 51 | 52 | Building HTML files 53 | ------------------- 54 | 55 | The `proton start` webserver is good for local development, but when it's time to 56 | deploy your site, you will need to build your files. This process outputs raw 57 | HTML files for your entire site (for the dynamic files), with Proton translating 58 | any files that need translation (e.g., HAML and ERB files). 59 | 60 | Build your files by typing this in the command prompt: 61 | 62 | $ proton build 63 | 64 | This will create a folder called `public/` where the built files are stored. 65 | You can now deploy this folder to your webserver. 66 | 67 | -------------------------------------------------------------------------------- /manual/introduction/installation.md: -------------------------------------------------------------------------------- 1 | title: Installation 2 | position: 1 3 | -- 4 | 5 | ## Requirements 6 | 7 | First, make sure that you have Ruby (>= version 1.8) installed. You can do this 8 | by typing `ruby --version` in the command line. 9 | 10 | - For Mac users, there's no need to do anything. Ruby comes with the OS by default. 11 | - For Windows users, I don't know. 12 | - For Ubuntu users, `sudo apt-get install ruby`. 13 | 14 | ## Installation 15 | 16 | Install Proton by typing: 17 | 18 | $ gem install proton 19 | 20 | If this process fails, you can instead try `sudo gem install proton`. 21 | 22 | -------------------------------------------------------------------------------- /manual/introduction/layouts.md: -------------------------------------------------------------------------------- 1 | title: Layouts 2 | -- 3 | 4 | Defining layouts 5 | ---------------- 6 | 7 | 1. Create a file called layouts/default.haml (or .erb) 8 | 2. use `yield` to show the page's contents 9 | 3. Voila 10 | 11 | Using your own layouts 12 | ---------------------- 13 | 14 | Use the `layout` metadata key. See the next section. 15 | -------------------------------------------------------------------------------- /manual/introduction/metadata.md: -------------------------------------------------------------------------------- 1 | title: Metadata 2 | -- 3 | 4 | You may include metadata for pages by placing a YAML document at the beginning 5 | of your page files. Be sure to separate your actual page from the metadata 6 | using two hyphens (`--`)! 7 | 8 | [mypage.haml (haml)] 9 | title: This is my page 10 | author: Jason White 11 | -- 12 | %div 13 | -# You may access metadata in using `page.meta.`. 14 | %h1= page.meta.title 15 | %cite 16 | by 17 | = page.meta.author 18 | 19 | Special metadata keys 20 | --------------------- 21 | 22 | Proton has a few reserved keys. 23 | 24 | ### title 25 | 26 | You may define a title for a page. You may then access this using `page.title`. 27 | 28 | [mypage-two.haml (haml)] 29 | title: This is my page 30 | -- 31 | %h1= page.title 32 | 33 | This shows: 34 | 35 |

This is my page

36 | 37 | If you do not define a title for a page, Proton automatically uses the page's 38 | filename instead. 39 | 40 | [mypage-three.haml (haml)] 41 | %h1= page.title 42 | 43 | Output: 44 | 45 |

mypage-three

46 | 47 | ### position 48 | 49 | You may manually define the order of your pages using the 'position' key. 50 | 51 | # about.haml 52 | title: About us 53 | position: 1 54 | -- 55 | 56 | # services.haml 57 | title: Services 58 | position: 2 59 | -- 60 | 61 | # contact.haml 62 | title: Contact us 63 | position: 9 64 | -- 65 | 66 | This will affect the sort order of menus and such. Specifically, it the 67 | outputs of functions such as `page.children`, `page.siblings`, `page.next`, 68 | and so on. 69 | 70 | The pages will then be ordered like so: 71 | 72 | - About us 73 | - Services 74 | - Contact us 75 | 76 | If positions have not been defined, they will be sorted alphabetically by 77 | filename, i.e.: 78 | 79 | - About us 80 | - Contact us 81 | - Services 82 | 83 | ### layout 84 | 85 | By default, a page will use the `default` layout. To change this, simply 86 | define a layout key in your metadata: 87 | 88 | [products/camera_cx-300.haml (yaml)] 89 | title: CX-300 Camera 90 | layout: product 91 | 92 | This will search for `layouts/product.*` (whichever extension it finds) in 93 | your project, and use that as the layout. (This is assuming, of course, that 94 | you haven't changed the default `layouts/` path in your Proton config file.) 95 | -------------------------------------------------------------------------------- /manual/introduction/partials.md: -------------------------------------------------------------------------------- 1 | title: Partials 2 | -- 3 | A partial is a snippet of code that you can reuse in any page of your site. 4 | This is particularly useful for repetitive sections, and for sections that may 5 | make your files too large to manage. 6 | 7 | Creating partials 8 | ----------------- 9 | 10 | Put your partial file anywhere in the `layouts` folder, e.g.: 11 | 12 | [layouts/shared/sidebar.erb (html)] 13 |
14 |

Sidebar

15 |
16 |

This is a sidebar partial defined in a separate file.

17 |
18 |

19 | 20 | In your site's files, you can invoke a partial through: 21 | 22 | [site/index.html.erb (html)] 23 |

Partial:

24 | <%= partial 'shared/sidebar' %> 25 | End of partial. 26 | This is now text from index.html. 27 | 28 | This will output: 29 | 30 | [public/index.html (html)] 31 |

Partial:

32 |
33 |

Sidebar

34 |
35 |

This is a sidebar partial defined in a separate file.

36 |
37 |

38 | End of partial. 39 | This is now text from index.html. 40 | 41 | Partials with local variables 42 | ----------------------------- 43 | 44 | You can define a partial with some local variables that will be passed 45 | to it by the caller. 46 | 47 | [layouts/shared/product.erb (html)] 48 |
49 |
50 |

<%= name %>

51 |
52 |
53 |

<%= description %>

54 |
55 |
56 | 57 | In your files, call a partial by: 58 | 59 | [site/index.html.erb (ruby)] 60 | <%= partial 'shared/product', { :name => '5MP Camera CX-300', :description => 'This is a camera with an adjustable focal length and Bluetooth support.' } %> 61 | 62 | Partials in HAML files 63 | ---------------------- 64 | 65 | HAML support in Proton has the `escape_html` option on by default. You 66 | will need to use `!= partial` instead of `= partial`. 67 | 68 | [(ruby)] 69 | -# Don't forget the exclamation point! 70 | != partial 'shared/product' 71 | 72 | If you omit the `!`, the partial will be rendered with it's HTML code 73 | escaped. 74 | -------------------------------------------------------------------------------- /manual/introduction/template_languages.md: -------------------------------------------------------------------------------- 1 | title: Template languages 2 | -- 3 | 4 | Proton comes with support for some common template languages. This means you 5 | can write your site in a language like Markdown or HAML, and have Proton take 6 | care of translating them accordingly. 7 | 8 | If a file ends in one of Proton's supported file extensions (like `.haml`), it 9 | will be stripped out and the file will be rendered using the template engine 10 | in that extension (in this case, HAML). 11 | 12 | Supported languages 13 | ------------------- 14 | 15 | Proton supports the following languages out-of-the-box: 16 | 17 | - HTML template languages 18 | - `.haml` (HAML) 19 | - `.md` (Markdown) 20 | - `.textile` (Textile) 21 | - `.erb` (ERB, Embedded Ruby) 22 | 23 | - CSS template languages 24 | - `.less` (LessCSS) 25 | - `.sass` (Sass) 26 | - `.scss` (Sass CSS) 27 | 28 | - JavaScript 29 | - `.coffee` (CoffeeScript) 30 | 31 | This means that the following files will be translated accordingly: 32 | 33 | - `products.haml` becomes `products.html` (rendered through HAML) 34 | - `control.less` becomes `control.css` (rendered through Less CSS) 35 | - `site.xml.erb` becomes `site.xml` (rendered through Embedded Ruby) 36 | 37 | Example 38 | ------- 39 | 40 | When creating a new site, have a look at `index.haml`. 41 | 42 | ... 43 | 44 | Headers 45 | ------- 46 | 47 | ... 48 | 49 | Layouts 50 | ------- 51 | 52 | Layouts are supported for HAML, Markdown, Textile and ERB languages. 53 | 54 | ... 55 | 56 | Embedded Ruby features 57 | ---------------------- 58 | 59 | Some languages (like HAML and ERB) has support for embedding Ruby code in the 60 | documents. This will let you do some nifty things in Proton: 61 | 62 | - Partials 63 | - Helpers 64 | -------------------------------------------------------------------------------- /manual/proton_build.md: -------------------------------------------------------------------------------- 1 | title: proton build 2 | page_type: command 3 | brief: Builds a Proton project. 4 | -- 5 | ## Usage 6 | 7 | $ proton build 8 | 9 | ## Description 10 | 11 | Builds. 12 | 13 | -------------------------------------------------------------------------------- /manual/proton_create.md: -------------------------------------------------------------------------------- 1 | title: proton create 2 | page_type: command 3 | brief: Creates a Proton project. 4 | -- 5 | ## Usage 6 | 7 | $ proton create NAME 8 | 9 | ## Description 10 | 11 | Creates a project in the folder NAME. 12 | 13 | ## Example 14 | 15 | $ proton create my_project 16 | 17 | ## See also 18 | 19 | - [proton rack](rack.html) - Makes a project Rack-compatible for deployment 20 | to Passenger or Heroku. 21 | -------------------------------------------------------------------------------- /manual/proton_rack.md: -------------------------------------------------------------------------------- 1 | title: proton rack 2 | page_type: command 3 | brief: Makes a Proton project Rack-compatible. 4 | -- 5 | ## Usage 6 | 7 | $ proton rack 8 | 9 | ## Description 10 | 11 | The current project will be Rack compatible by creating a config.ru and 12 | Gemfiles. 13 | 14 | ## Example 15 | 16 | Create a project: 17 | 18 | ~$ proton create my_project 19 | 20 | ~$ cd my_project 21 | 22 | Now, make it Rack compatible: 23 | 24 | ~/my_project$ proton rack 25 | 26 | create Gemfile 27 | create Gemfile.lock 28 | create config.ru 29 | 30 | Now try running it as a Rack application. 31 | 32 | ~/my_project$ thin start 33 | 34 | >> Using rack adapter 35 | >> Thin web server (v1.2.7 codename No Hup) 36 | >> Maximum connections set to 1024 37 | >> Listening on 0.0.0.0:9393, press Ctrl+C to stop 38 | -------------------------------------------------------------------------------- /manual/proton_start.md: -------------------------------------------------------------------------------- 1 | title: proton start 2 | page_type: command 3 | brief: Starts a preview server where you can view your changes in real-time. 4 | -- 5 | ## Usage 6 | 7 | $ proton start 8 | 9 | ## Description 10 | 11 | Starts a web server. 12 | 13 | -------------------------------------------------------------------------------- /manual/tips.md: -------------------------------------------------------------------------------- 1 | title: Tips 2 | position: 3 3 | page_type: section 4 | -- 5 | 6 | Here are some tips and tricks! 7 | 8 | -------------------------------------------------------------------------------- /manual/tips/simple_folder_structure.md: -------------------------------------------------------------------------------- 1 | title: Simpler folder structure 2 | -- 3 | The default folder structure looks like this: 4 | 5 | project/ 6 | Protonfile 7 | layouts/ 8 | partials/ 9 | public/ 10 | extensions/ 11 | site/ 12 | about.html 13 | contact.html 14 | 15 | Here is a cleaner structure often used in simpler projects: 16 | 17 | project/ 18 | about.html 19 | contact.html 20 | 21 | .protonrc 22 | _/ 23 | layouts/ 24 | partials/ 25 | public/ 26 | extensions/ 27 | 28 | You may do this by editing your Proton config file like so: 29 | 30 | site_path: . 31 | layouts_path: _/layouts 32 | extensions_path: _/extensions 33 | partials_path: _/partials 34 | output_path: _/public 35 | 36 | Optionally, you can rename `Protonfile` to `.protonrc` to make it even 37 | cleaner. 38 | -------------------------------------------------------------------------------- /manual/tips/subclassing_page.md: -------------------------------------------------------------------------------- 1 | title: Subclassing Page 2 | -- 3 | You may subclass the [Proton::Page](../api/proton/page.md) class. 4 | 5 | ## Subclassing in an extension 6 | 7 | Create an extension to subclass it: 8 | 9 | [_extensions/post/post.rb (rb)] 10 | class Proton::Page::Post < Proton::Page 11 | # Put some extra methods here 12 | def css_class 13 | title.downcase.gsub(' ', '-') 14 | end 15 | end 16 | 17 | ## Using your subclass 18 | 19 | Now in your files, specify the type with `type` metadata: 20 | 21 | [hello.textile (textile)] 22 | title: Hello world 23 | type: post 24 | layout: default 25 | -- 26 | Hello, world! This page will be of type Post. 27 | 28 | ## Subclasses in posts 29 | 30 | Now in the layout, the `page` variable will be an instance of 31 | `Proton::Page::Post`. 32 | 33 | [_layouts/default.haml (haml)] 34 | %body 35 | - if page.is_a? Proton::Page::Post 36 | %h1{class: page.css_class} 37 | Post: 38 | = page.title 39 | 40 | ## Changing default layouts per subclass 41 | 42 | You can redefine `Page::default_layout` to change the default layout for the 43 | page subclass. 44 | 45 | class Proton::Page::Post < Proton::Page 46 | def default_layout 47 | 'post' if html? 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /manual/tips/tilt_build_options.md: -------------------------------------------------------------------------------- 1 | title: Tilt build options 2 | -- 3 | Add these to `Protonfile`. 4 | 5 | Optional options for layout engines. 6 | 7 | tilt_options: 8 | haml: 9 | escape_html: true 10 | scss: 11 | load_paths: [ 'css' ] 12 | style: :compact 13 | line_numbers: true 14 | 15 | To disable CSS compression on the output, add these to your `Protonfile`: 16 | 17 | tilt_build_options: 18 | scss: 19 | style: :compact 20 | line_numbers: false 21 | -------------------------------------------------------------------------------- /proton.gemspec: -------------------------------------------------------------------------------- 1 | # gem build *.gemspec 2 | # gem push *.gem 3 | # 4 | require "./lib/proton/version" 5 | Gem::Specification.new do |s| 6 | s.name = "proton" 7 | s.version = Proton.version 8 | s.summary = "Prototyping tool / static site generator." 9 | s.description = "Proton lets you create static websites from a bunch of files written in HAML, Textile, Sass, or any other templating language." 10 | s.authors = ["Rico Sta. Cruz"] 11 | s.email = ["rico@sinefunc.com"] 12 | s.homepage = "http://github.com/sinefunc/proton" 13 | s.files = Dir["{bin,lib,test,data}/**/*", "*.md", "Rakefile", "AUTHORS"] 14 | s.executables = ["proton"] 15 | 16 | s.add_dependency "shake", "~> 0.1" 17 | s.add_dependency "tilt", "~> 1.3.2" 18 | s.add_dependency "cuba", "~> 2.0.0" 19 | s.add_dependency "hashie", "~> 1.0.0" 20 | s.add_dependency "haml", "~> 3.1.1" 21 | s.add_dependency "sass", "~> 3.1.1" 22 | s.add_dependency "compass", "~> 0.11.1" 23 | s.add_dependency "RedCloth", "~> 4.2.3" 24 | s.add_dependency "maruku", "~> 0.6.0" 25 | 26 | s.add_development_dependency "less" 27 | s.add_development_dependency "maruku" 28 | end 29 | -------------------------------------------------------------------------------- /test/fixture/build_options/control/page.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sinefunc/proton/cd3539758f9e61d669b938f370c0e67ecabdf5b4/test/fixture/build_options/control/page.html -------------------------------------------------------------------------------- /test/fixture/build_options/control/style.css: -------------------------------------------------------------------------------- 1 | div a{color:red} 2 | -------------------------------------------------------------------------------- /test/fixture/build_options/hyde.conf: -------------------------------------------------------------------------------- 1 | hyde_requirement: 0.1 2 | site_path: site 3 | extensions_path: extensions 4 | output_path: public 5 | ignore: 6 | - **/*~ 7 | - **/compass/**/* 8 | - **/_*.scss 9 | 10 | tilt_options: 11 | haml: 12 | x: 2 13 | scss: 14 | :line_numbers: true 15 | 16 | tilt_build_options: 17 | scss: 18 | :line_numbers: false 19 | -------------------------------------------------------------------------------- /test/fixture/build_options/site/page.haml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sinefunc/proton/cd3539758f9e61d669b938f370c0e67ecabdf5b4/test/fixture/build_options/site/page.haml -------------------------------------------------------------------------------- /test/fixture/build_options/site/style.scss: -------------------------------------------------------------------------------- 1 | div { a { color: red; } } 2 | -------------------------------------------------------------------------------- /test/fixture/compass/hyde.conf: -------------------------------------------------------------------------------- 1 | output_path: public 2 | site_path: site 3 | ignore: 4 | - control 5 | -------------------------------------------------------------------------------- /test/fixture/compass/site/style.scss: -------------------------------------------------------------------------------- 1 | @import 'compass/css3'; 2 | 3 | #foo { 4 | @include border-radius(4px); 5 | } 6 | -------------------------------------------------------------------------------- /test/fixture/empty_config/hyde.conf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sinefunc/proton/cd3539758f9e61d669b938f370c0e67ecabdf5b4/test/fixture/empty_config/hyde.conf -------------------------------------------------------------------------------- /test/fixture/extensions/control/index.html: -------------------------------------------------------------------------------- 1 |

hey

2 | -------------------------------------------------------------------------------- /test/fixture/extensions/extensions/a/a.rb: -------------------------------------------------------------------------------- 1 | $extension_loaded = 'aoeu' 2 | -------------------------------------------------------------------------------- /test/fixture/extensions/extensions/hi.rb: -------------------------------------------------------------------------------- 1 | $hi = 1 2 | -------------------------------------------------------------------------------- /test/fixture/extensions/hyde.conf: -------------------------------------------------------------------------------- 1 | hyde_requirement: 0.1 2 | site_path: site 3 | extensions_path: extensions 4 | output_path: public 5 | ignore: 6 | - **/*~ 7 | - **/compass/**/* 8 | - **/_*.scss 9 | -------------------------------------------------------------------------------- /test/fixture/extensions/site/index.haml: -------------------------------------------------------------------------------- 1 | %h1 hey 2 | -------------------------------------------------------------------------------- /test/fixture/fail_type/control/about/index.html: -------------------------------------------------------------------------------- 1 | Parent: 2 | Back to parent 3 | -------------------------------------------------------------------------------- /test/fixture/fail_type/control/about/us.html: -------------------------------------------------------------------------------- 1 | Parent: 2 | Back to parent 3 | -------------------------------------------------------------------------------- /test/fixture/fail_type/control/index.html: -------------------------------------------------------------------------------- 1 |

Yo

2 | -------------------------------------------------------------------------------- /test/fixture/fail_type/hyde.conf: -------------------------------------------------------------------------------- 1 | hyde_requirement: 0.1 2 | site_path: site 3 | extensions_path: extensions 4 | output_path: public 5 | ignore: 6 | - **/*~ 7 | - **/compass/**/* 8 | - **/_*.scss 9 | -------------------------------------------------------------------------------- /test/fixture/fail_type/site/index.haml: -------------------------------------------------------------------------------- 1 | title: Hello there 2 | type: nonexistent 3 | -- 4 | #ok 5 | -------------------------------------------------------------------------------- /test/fixture/high_version/hyde.conf: -------------------------------------------------------------------------------- 1 | hyde_requirement: 9000.0 2 | -------------------------------------------------------------------------------- /test/fixture/high_version_2/hyde.conf: -------------------------------------------------------------------------------- 1 | requirement: 9000.0 2 | -------------------------------------------------------------------------------- /test/fixture/html/control/index.html: -------------------------------------------------------------------------------- 1 |

Welcome.

2 | Hello 3 | -------------------------------------------------------------------------------- /test/fixture/html/hyde.conf: -------------------------------------------------------------------------------- 1 | hyde_requirement: 0.1 2 | site_path: site 3 | extensions_path: extensions 4 | output_path: public 5 | ignore: 6 | - **/*~ 7 | - **/compass/**/* 8 | - **/_*.scss 9 | -------------------------------------------------------------------------------- /test/fixture/html/site/index.html: -------------------------------------------------------------------------------- 1 |

Welcome.

2 | <%= "Hello" %> 3 | -------------------------------------------------------------------------------- /test/fixture/ignores/control/about.html: -------------------------------------------------------------------------------- 1 |

ello

2 | -------------------------------------------------------------------------------- /test/fixture/ignores/hyde.conf: -------------------------------------------------------------------------------- 1 | hyde_requirement: 0.1 2 | site_path: site 3 | extensions_path: extensions 4 | output_path: public 5 | partials_path: site 6 | ignore: 7 | - **/*~ 8 | - **/h* 9 | - **/compass/**/* 10 | - **/_*.scss 11 | -------------------------------------------------------------------------------- /test/fixture/ignores/site/about.haml: -------------------------------------------------------------------------------- 1 | %h1 ello 2 | -------------------------------------------------------------------------------- /test/fixture/ignores/site/hi.haml: -------------------------------------------------------------------------------- 1 | xxx 2 | -------------------------------------------------------------------------------- /test/fixture/metadata/control/index.html: -------------------------------------------------------------------------------- 1 |

Hyde is it

2 |
title: Hello world!
3 | ---
4 | 
<h1>Hi</hi>
5 | -------------------------------------------------------------------------------- /test/fixture/metadata/hyde.conf: -------------------------------------------------------------------------------- 1 | hyde_requirement: 0.1 2 | site_path: site 3 | extensions_path: extensions 4 | output_path: public 5 | ignore: 6 | - **/*~ 7 | - **/compass/**/* 8 | - **/_*.scss 9 | -------------------------------------------------------------------------------- /test/fixture/metadata/site/index.haml: -------------------------------------------------------------------------------- 1 | title: Hyde is it 2 | --- 3 | %h1= meta.title 4 | %pre.prettyprint.lang-html 5 | :escaped 6 | title: Hello world! 7 | --- 8 | .highlight="

Hi" 9 | -------------------------------------------------------------------------------- /test/fixture/nested_layout/control/index.html: -------------------------------------------------------------------------------- 1 |

Boo!

2 |
10
3 | -------------------------------------------------------------------------------- /test/fixture/nested_layout/hyde.conf: -------------------------------------------------------------------------------- 1 | hyde_requirement: 0.1 2 | site_path: site 3 | extensions_path: extensions 4 | layouts_path: layouts 5 | output_path: public 6 | ignore: 7 | - **/*~ 8 | - **/compass/**/* 9 | - **/_*.scss 10 | -------------------------------------------------------------------------------- /test/fixture/nested_layout/layouts/default.haml: -------------------------------------------------------------------------------- 1 | #default!= yield 2 | #number!= page.ten 3 | -------------------------------------------------------------------------------- /test/fixture/nested_layout/layouts/post.haml: -------------------------------------------------------------------------------- 1 | layout: default 2 | -- 3 | %h1!= yield 4 | -------------------------------------------------------------------------------- /test/fixture/nested_layout/site/index.haml: -------------------------------------------------------------------------------- 1 | layout: post 2 | ten: 10 3 | -- 4 | Boo! 5 | -------------------------------------------------------------------------------- /test/fixture/one/control/about/index.css: -------------------------------------------------------------------------------- 1 | div{color:red} 2 | -------------------------------------------------------------------------------- /test/fixture/one/control/about/us.html: -------------------------------------------------------------------------------- 1 |

hi

2 | -------------------------------------------------------------------------------- /test/fixture/one/control/cheers.html: -------------------------------------------------------------------------------- 1 | 2 |

Site

3 |
4 |
lo.
5 | 6 | -------------------------------------------------------------------------------- /test/fixture/one/control/css/bar.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sinefunc/proton/cd3539758f9e61d669b938f370c0e67ecabdf5b4/test/fixture/one/control/css/bar.css -------------------------------------------------------------------------------- /test/fixture/one/control/css/style.css: -------------------------------------------------------------------------------- 1 | dir{color:#332211} 2 | -------------------------------------------------------------------------------- /test/fixture/one/control/hello.html: -------------------------------------------------------------------------------- 1 | 2 |

Site

3 |
4 |

Welcome!

5 | 6 | -------------------------------------------------------------------------------- /test/fixture/one/control/hi.html: -------------------------------------------------------------------------------- 1 | Hello. 2 | -------------------------------------------------------------------------------- /test/fixture/one/control/images/bar.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sinefunc/proton/cd3539758f9e61d669b938f370c0e67ecabdf5b4/test/fixture/one/control/images/bar.gif -------------------------------------------------------------------------------- /test/fixture/one/control/images/baz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sinefunc/proton/cd3539758f9e61d669b938f370c0e67ecabdf5b4/test/fixture/one/control/images/baz.png -------------------------------------------------------------------------------- /test/fixture/one/control/images/foo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sinefunc/proton/cd3539758f9e61d669b938f370c0e67ecabdf5b4/test/fixture/one/control/images/foo.jpg -------------------------------------------------------------------------------- /test/fixture/one/control/index.html: -------------------------------------------------------------------------------- 1 |
    2 |
  • Home
  • 3 |
  • About us
  • 4 |
5 |

Home page

6 | <a> 7 | 8 | -------------------------------------------------------------------------------- /test/fixture/one/hyde.conf: -------------------------------------------------------------------------------- 1 | hyde_requirement: "0.1" 2 | site_path: site 3 | layouts_path: layouts 4 | partials_path: partials 5 | output_path: public 6 | ignore: 7 | - **/*~ 8 | - **/compass/**/* 9 | - **/_*.scss 10 | -------------------------------------------------------------------------------- /test/fixture/one/layouts/default.haml: -------------------------------------------------------------------------------- 1 | %html 2 | %h1 Site 3 | %hr 4 | #content!= yield 5 | -------------------------------------------------------------------------------- /test/fixture/one/partials/menu.haml: -------------------------------------------------------------------------------- 1 | %ul 2 | %li Home 3 | %li About us 4 | -------------------------------------------------------------------------------- /test/fixture/one/site/about/index.scss: -------------------------------------------------------------------------------- 1 | div { color: red; } 2 | -------------------------------------------------------------------------------- /test/fixture/one/site/about/us.haml: -------------------------------------------------------------------------------- 1 | layout: false 2 | -- 3 | %h1 hi 4 | -------------------------------------------------------------------------------- /test/fixture/one/site/cheers.html.haml: -------------------------------------------------------------------------------- 1 | lo. 2 | -------------------------------------------------------------------------------- /test/fixture/one/site/css/bar.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sinefunc/proton/cd3539758f9e61d669b938f370c0e67ecabdf5b4/test/fixture/one/site/css/bar.scss -------------------------------------------------------------------------------- /test/fixture/one/site/css/style.scss: -------------------------------------------------------------------------------- 1 | $red: #321; 2 | dir { color: $red; } 3 | -------------------------------------------------------------------------------- /test/fixture/one/site/hello.haml: -------------------------------------------------------------------------------- 1 | hello: world 2 | -- 3 | %h1 Welcome! 4 | -------------------------------------------------------------------------------- /test/fixture/one/site/hi.html: -------------------------------------------------------------------------------- 1 | layout: false 2 | -- 3 | Hello. 4 | -------------------------------------------------------------------------------- /test/fixture/one/site/images/bar.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sinefunc/proton/cd3539758f9e61d669b938f370c0e67ecabdf5b4/test/fixture/one/site/images/bar.gif -------------------------------------------------------------------------------- /test/fixture/one/site/images/baz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sinefunc/proton/cd3539758f9e61d669b938f370c0e67ecabdf5b4/test/fixture/one/site/images/baz.png -------------------------------------------------------------------------------- /test/fixture/one/site/images/foo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sinefunc/proton/cd3539758f9e61d669b938f370c0e67ecabdf5b4/test/fixture/one/site/images/foo.jpg -------------------------------------------------------------------------------- /test/fixture/one/site/index.haml: -------------------------------------------------------------------------------- 1 | layout: false 2 | lol: 3 | -- 4 | != partial :'menu' 5 | %h2 Home page 6 | = page.meta.lol 7 | != page.meta.lol 8 | -------------------------------------------------------------------------------- /test/fixture/parent/control/about/index.html: -------------------------------------------------------------------------------- 1 | Parent: 2 | Back to parent 3 | -------------------------------------------------------------------------------- /test/fixture/parent/control/about/us.html: -------------------------------------------------------------------------------- 1 | Parent: 2 | Back to parent 3 | -------------------------------------------------------------------------------- /test/fixture/parent/control/index.html: -------------------------------------------------------------------------------- 1 |

Yo

2 | -------------------------------------------------------------------------------- /test/fixture/parent/hyde.conf: -------------------------------------------------------------------------------- 1 | hyde_requirement: 0.1 2 | site_path: site 3 | extensions_path: extensions 4 | output_path: public 5 | ignore: 6 | - **/*~ 7 | - **/compass/**/* 8 | - **/_*.scss 9 | -------------------------------------------------------------------------------- /test/fixture/parent/site/about/index.haml: -------------------------------------------------------------------------------- 1 | Parent: 2 | - if parent 3 | %a{:href => parent.path} Back to parent 4 | -------------------------------------------------------------------------------- /test/fixture/parent/site/about/us.haml: -------------------------------------------------------------------------------- 1 | Parent: 2 | - if parent 3 | %a{:href => parent.path} Back to parent 4 | -------------------------------------------------------------------------------- /test/fixture/parent/site/index.haml: -------------------------------------------------------------------------------- 1 | title: Hello there 2 | -- 3 | %h1 Yo 4 | -------------------------------------------------------------------------------- /test/fixture/sort/control/about.html: -------------------------------------------------------------------------------- 1 |
  • 2 | One, intrepid 3 |
  • 4 |
  • 5 | Two, hardy 6 |
  • 7 | -------------------------------------------------------------------------------- /test/fixture/sort/control/about/hardy.html: -------------------------------------------------------------------------------- 1 | ... 2 | -------------------------------------------------------------------------------- /test/fixture/sort/control/about/intrepid.html: -------------------------------------------------------------------------------- 1 | ... 2 | -------------------------------------------------------------------------------- /test/fixture/sort/hyde.conf: -------------------------------------------------------------------------------- 1 | hyde_requirement: 0.1 2 | site_path: site 3 | extensions_path: extensions 4 | output_path: public 5 | ignore: 6 | - **/*~ 7 | - **/compass/**/* 8 | - **/_*.scss 9 | -------------------------------------------------------------------------------- /test/fixture/sort/site/about.haml: -------------------------------------------------------------------------------- 1 | - children.each do |p| 2 | %li 3 | %a{:href => p.path}= p 4 | -------------------------------------------------------------------------------- /test/fixture/sort/site/about/hardy.haml: -------------------------------------------------------------------------------- 1 | position: 2 2 | title: Two, hardy 3 | -- 4 | ="..." 5 | -------------------------------------------------------------------------------- /test/fixture/sort/site/about/intrepid.haml: -------------------------------------------------------------------------------- 1 | position: 1 2 | title: One, intrepid 3 | -- 4 | ="..." 5 | -------------------------------------------------------------------------------- /test/fixture/subclass/control/index.html: -------------------------------------------------------------------------------- 1 |

    hello-there

    2 | -------------------------------------------------------------------------------- /test/fixture/subclass/extensions/a/a.rb: -------------------------------------------------------------------------------- 1 | class Proton::Page::Post < Proton::Page 2 | def css_class 3 | title.downcase.gsub(' ', '-') 4 | end 5 | 6 | def default_layout 7 | 'post' if html? 8 | end 9 | 10 | # Alias 11 | ::Post = self 12 | end 13 | -------------------------------------------------------------------------------- /test/fixture/subclass/hyde.conf: -------------------------------------------------------------------------------- 1 | hyde_requirement: 0.1 2 | site_path: site 3 | extensions_path: extensions 4 | output_path: public 5 | layouts_path: layouts 6 | ignore: 7 | - **/*~ 8 | - **/compass/**/* 9 | - **/_*.scss 10 | -------------------------------------------------------------------------------- /test/fixture/subclass/layouts/default.haml: -------------------------------------------------------------------------------- 1 | Wrong! 2 | -------------------------------------------------------------------------------- /test/fixture/subclass/layouts/post.haml: -------------------------------------------------------------------------------- 1 | #post!= yield 2 | -------------------------------------------------------------------------------- /test/fixture/subclass/site/index.haml: -------------------------------------------------------------------------------- 1 | title: Hello there 2 | type: post 3 | -- 4 | %h1= page.css_class 5 | -------------------------------------------------------------------------------- /test/helper.rb: -------------------------------------------------------------------------------- 1 | $:.push File.expand_path('../../lib', __FILE__) 2 | 3 | require 'rubygems' if !Object.respond_to?(:gem) 4 | 5 | gem "contest", "~> 0.1" 6 | 7 | require 'proton' 8 | require 'contest' 9 | 10 | class TestCase < Test::Unit::TestCase 11 | # Shorthand 12 | Page = Proton::Page 13 | Project = Proton::Project 14 | 15 | def fixture(*a) 16 | path = File.expand_path('../fixture', __FILE__) 17 | File.join path, *a 18 | end 19 | 20 | def build(path) 21 | @project = Proton::Project.new(path) 22 | @project.pages.each { |p| p.write } 23 | @project 24 | end 25 | 26 | def unbuild(project=@project) 27 | FileUtils.rm_rf project.path(:output) 28 | end 29 | end 30 | 31 | class Proton::Set 32 | # Because 1.8.6 doesn't support map(&:path) 33 | def paths 34 | map { |page| page.path } 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /test/unit/build_options_test.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../../helper', __FILE__) 2 | 3 | class BuildOptionsTest < TestCase 4 | setup do 5 | @path = fixture('build_options') 6 | @project = Project.new(@path) 7 | Dir.chdir @path 8 | end 9 | 10 | test "yada" do 11 | raw = Page['/style.css'].to_html 12 | built = Page['/style.css'].to_html({}, :build => true) 13 | 14 | assert !built.include?("line 1") 15 | assert raw.include?("line 1") 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /test/unit/extensions_test.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../../helper', __FILE__) 2 | 3 | class ExtensionsTest < TestCase 4 | setup do 5 | $extension_loaded = nil 6 | @project = build fixture('extensions') 7 | end 8 | 9 | teardown do 10 | unbuild @project 11 | end 12 | 13 | test "extensions" do 14 | assert $extension_loaded == "aoeu" 15 | assert $hi == 1 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /test/unit/fixture_test.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../../helper', __FILE__) 2 | 3 | class FixtureTest < TestCase 4 | def assert_fixture_works(path, options={}) 5 | build_fixture(path, options) { |control, var| 6 | assert File.exists?(var), "#{var} doesn't exist" 7 | if read(control) != read(var) 8 | flunk "Failed in #{var}\n" + 9 | "Control:\n" + 10 | read(control).gsub(/^/, '| ') + "\n\n" + 11 | "Variable:\n" + 12 | read(var).gsub(/^/, '| ') 13 | end 14 | } 15 | end 16 | 17 | def assert_fixture_fails(path, error=Proton::Error, &blk) 18 | begin 19 | build_fixture(path) 20 | rescue error => e 21 | yield e 22 | else 23 | flunk "Assertion failed" 24 | end 25 | end 26 | 27 | 28 | def build_fixture(path, options={}, &blk) 29 | # Build 30 | project = build path 31 | 32 | options[:control_path] ||= '_control' 33 | options[:public_path] ||= '_public' 34 | 35 | control_path = project.root(options[:control_path]) 36 | public_path = project.root(options[:public_path]) 37 | 38 | from = Dir["#{control_path}/**/*"].map { |dir| dir.gsub(control_path, '') }.sort 39 | to = Dir["#{public_path}/**/*"].map { |dir| dir.gsub(public_path, '') }.sort 40 | 41 | assert_equal from, to, "The build happened to make less files" 42 | 43 | Dir["#{control_path}/**/*"].each do |control| 44 | next unless File.file?(control) 45 | var = control.sub(control_path, public_path) 46 | yield control, var 47 | end if block_given? 48 | end 49 | 50 | def read(file) 51 | File.open(file) { |f| f.read } 52 | end 53 | 54 | teardown do 55 | # Remove the generated 56 | ( Dir[fixture('*', 'public')] + 57 | Dir[fixture('*', '_public')] 58 | ).each { |dir| FileUtils.rm_rf dir } 59 | end 60 | 61 | test "fixture one" do 62 | assert_fixture_works fixture('one') 63 | end 64 | 65 | test "fixture subclass" do 66 | assert_fixture_works fixture('subclass') 67 | end 68 | 69 | test "fixture extensions" do 70 | assert_fixture_works fixture('extensions') 71 | end 72 | 73 | test "fixture parent" do 74 | assert_fixture_works fixture('parent') 75 | end 76 | 77 | test "fixture sort" do 78 | assert_fixture_works fixture('sort') 79 | end 80 | 81 | test "fixture ignores" do 82 | assert_fixture_works fixture('ignores') 83 | end 84 | 85 | test "fixture metadata" do 86 | assert_fixture_works fixture('metadata') 87 | end 88 | 89 | test "fixture nested_layout" do 90 | assert_fixture_works fixture('nested_layout') 91 | end 92 | 93 | test "fixture build_options" do 94 | assert_fixture_works fixture('build_options') 95 | end 96 | 97 | test "compass support" do 98 | assert_fixture_works fixture('compass') 99 | end 100 | 101 | test "fixture empty_config" do 102 | assert_fixture_works fixture('empty_config'), 103 | :control_path => '_control', 104 | :public_path => '_output' 105 | end 106 | 107 | test "fixture high_version" do 108 | assert_fixture_fails(fixture('high_version')) { |e| 109 | assert e.message.include?('>= 9000') 110 | } 111 | 112 | assert_fixture_fails(fixture('high_version_2')) { |e| 113 | assert e.message.include?('>= 9000') 114 | } 115 | end 116 | 117 | test "fixture fail_type" do 118 | assert_fixture_fails(fixture('fail_type')) { |e| 119 | assert e.message.include?('nonexistent') 120 | } 121 | end 122 | end 123 | -------------------------------------------------------------------------------- /test/unit/helper_test.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../../helper', __FILE__) 2 | 3 | class HelperTest < TestCase 4 | include Proton::Helpers 5 | 6 | test "rel" do 7 | assert_equal 'index.html', rel('index.html', '/about/index.html') 8 | assert_equal '../index.html', rel('/index.html', '/about/index.html') 9 | assert_equal '../foo/index.html', rel('/foo/index.html', '/about/index.html') 10 | assert_equal '../about/us.html', rel('/about/us.html', '/about/index.html') 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /test/unit/page_test.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../../helper', __FILE__) 2 | 3 | class PageTest < TestCase 4 | setup do 5 | @path = fixture('one') 6 | @project = Project.new(@path) 7 | Dir.chdir @path 8 | end 9 | 10 | test "root" do 11 | @page = Page['/'] 12 | assert @page.index? 13 | assert @page.root? 14 | end 15 | 16 | test "breadcrumbs" do 17 | assert_equal %w(/index.html /about/index.css), Page['/about/index.css'].breadcrumbs.paths 18 | assert_equal %w(/index.html /about/index.css /about/us.html), Page['/about/us.html'].breadcrumbs.paths 19 | assert_equal %w(/index.html /css/style.css), Page['/css/style.css'].breadcrumbs.paths 20 | assert_equal %w(/index.html), Page['/'].breadcrumbs.paths 21 | end 22 | 23 | test "parent" do 24 | assert Page['/'].parent.nil? 25 | assert Page['/css/style.css'].parent.path == '/index.html' 26 | end 27 | 28 | test "siblings" do 29 | # Because it has no parent, technically 30 | page = Page['/about/index.css'] 31 | assert page.siblings.empty? 32 | 33 | page = Page['/hello.html'] 34 | assert_equal %w(/cheers.html /hello.html /hi.html), page.siblings.paths 35 | end 36 | 37 | test "mimes" do 38 | assert !Page['/css/style.css'].html? 39 | assert Page['/'].html? 40 | assert_equal 'text/css', Page['/css/style.css'].mime_type 41 | assert_equal 'text/html', Page['/about/us.html'].mime_type 42 | assert_equal 'html', Page['/about/us.html'].default_ext 43 | assert_equal 'css', Page['/css/style.css'].default_ext 44 | end 45 | 46 | test "no layout" do 47 | page = Page['/hi.html'] 48 | assert_equal false, page.meta.layout 49 | assert_equal nil, page.layout 50 | assert_equal false, page.layout? 51 | assert_equal page.to_html, page.content 52 | end 53 | 54 | test "html pages should be intact" do 55 | page = Page['/hi'] 56 | assert_equal page.markup, page.content 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /test/unit/proton_test.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../../helper', __FILE__) 2 | 3 | class ProtonTest < TestCase 4 | setup do 5 | @path = fixture('one') 6 | @project = Project.new(@path) 7 | Dir.chdir @path 8 | end 9 | 10 | test "build" do 11 | @project.pages.each { |page| page.write } 12 | end 13 | 14 | test "accessible" do 15 | site = lambda { |*a| File.join(@path, 'site', *a) } 16 | 17 | # site/hi.html 18 | assert_equal Page['/cheers.html'].file, site['cheers.html.haml'] 19 | assert_equal Page['/hi.html'].file, site['hi.html'] 20 | assert_equal Page['/hi.yo'].file, site['hi.html'] 21 | assert_equal Page['/hi'].file, site['hi.html'] 22 | assert_equal Page['/css/style.css'].file, site['css/style.scss'] 23 | assert_equal Page['/css/style.css'].file, site['css/style.scss'] 24 | assert_equal Page['/about'].file, site['about/index.scss'] 25 | assert_equal Page['/'].file, site['/index.haml'] 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /test/unit/set_test.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../../helper', __FILE__) 2 | 3 | class SetTest < TestCase 4 | setup do 5 | @path = fixture('one') 6 | @project = Project.new(@path) 7 | Dir.chdir @path 8 | end 9 | 10 | test "breadcrumbs" do 11 | assert Page['/about/index.css'].breadcrumbs.is_a?(Proton::Set) 12 | end 13 | 14 | test "children" do 15 | assert Page['/'].children.is_a?(Proton::Set) 16 | end 17 | 18 | test "siblings" do 19 | assert Page['/about'].siblings.is_a?(Proton::Set) 20 | end 21 | 22 | test "children" do 23 | set = Page['/'].children.find(:hello => 'world') 24 | assert set.paths == ['/hello.html'] 25 | end 26 | end 27 | --------------------------------------------------------------------------------