proton 0.3.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +6 -0
- data/HISTORY.md +200 -0
- data/README.md +75 -0
- data/Rakefile +5 -0
- data/TODO.md +6 -0
- data/bin/proton +7 -0
- data/data/new_site/Protonfile +12 -0
- data/data/new_site/README.md +10 -0
- data/data/new_site/_layouts/default.haml +28 -0
- data/data/new_site/index.haml +5 -0
- data/data/rack/Gemfile +2 -0
- data/data/rack/Gemfile.lock +40 -0
- data/data/rack/config.ru +24 -0
- data/lib/proton.rb +78 -0
- data/lib/proton/cli.rb +227 -0
- data/lib/proton/cli/helpers.rb +89 -0
- data/lib/proton/compass_support.rb +8 -0
- data/lib/proton/config.rb +116 -0
- data/lib/proton/helpers.rb +126 -0
- data/lib/proton/layout.rb +20 -0
- data/lib/proton/meta.rb +17 -0
- data/lib/proton/page.rb +431 -0
- data/lib/proton/partial.rb +12 -0
- data/lib/proton/project.rb +176 -0
- data/lib/proton/server.rb +99 -0
- data/lib/proton/set.rb +32 -0
- data/lib/proton/version.rb +13 -0
- data/test/fixture/build_options/control/page.html +0 -0
- data/test/fixture/build_options/control/style.css +1 -0
- data/test/fixture/build_options/hyde.conf +18 -0
- data/test/fixture/build_options/site/page.haml +0 -0
- data/test/fixture/build_options/site/style.scss +1 -0
- data/test/fixture/compass/hyde.conf +4 -0
- data/test/fixture/compass/site/style.scss +5 -0
- data/test/fixture/empty_config/hyde.conf +0 -0
- data/test/fixture/extensions/control/index.html +1 -0
- data/test/fixture/extensions/extensions/a/a.rb +1 -0
- data/test/fixture/extensions/extensions/hi.rb +1 -0
- data/test/fixture/extensions/hyde.conf +8 -0
- data/test/fixture/extensions/site/index.haml +1 -0
- data/test/fixture/fail_type/control/about/index.html +2 -0
- data/test/fixture/fail_type/control/about/us.html +2 -0
- data/test/fixture/fail_type/control/index.html +1 -0
- data/test/fixture/fail_type/hyde.conf +8 -0
- data/test/fixture/fail_type/site/index.haml +4 -0
- data/test/fixture/high_version/hyde.conf +1 -0
- data/test/fixture/high_version_2/hyde.conf +1 -0
- data/test/fixture/html/control/index.html +2 -0
- data/test/fixture/html/hyde.conf +8 -0
- data/test/fixture/html/site/index.html +2 -0
- data/test/fixture/ignores/control/about.html +1 -0
- data/test/fixture/ignores/hyde.conf +10 -0
- data/test/fixture/ignores/site/about.haml +1 -0
- data/test/fixture/ignores/site/hi.haml +1 -0
- data/test/fixture/metadata/control/index.html +4 -0
- data/test/fixture/metadata/hyde.conf +8 -0
- data/test/fixture/metadata/site/index.haml +8 -0
- data/test/fixture/nested_layout/control/index.html +2 -0
- data/test/fixture/nested_layout/hyde.conf +9 -0
- data/test/fixture/nested_layout/layouts/default.haml +2 -0
- data/test/fixture/nested_layout/layouts/post.haml +3 -0
- data/test/fixture/nested_layout/site/index.haml +4 -0
- data/test/fixture/one/control/about/index.css +1 -0
- data/test/fixture/one/control/about/us.html +1 -0
- data/test/fixture/one/control/cheers.html +5 -0
- data/test/fixture/one/control/css/bar.css +0 -0
- data/test/fixture/one/control/css/style.css +1 -0
- data/test/fixture/one/control/hello.html +5 -0
- data/test/fixture/one/control/hi.html +1 -0
- data/test/fixture/one/control/images/bar.gif +0 -0
- data/test/fixture/one/control/images/baz.png +0 -0
- data/test/fixture/one/control/images/foo.jpg +0 -0
- data/test/fixture/one/control/index.html +7 -0
- data/test/fixture/one/hyde.conf +9 -0
- data/test/fixture/one/layouts/default.haml +4 -0
- data/test/fixture/one/partials/menu.haml +3 -0
- data/test/fixture/one/public/about/index.css +1 -0
- data/test/fixture/one/public/about/us.html +1 -0
- data/test/fixture/one/public/cheers.html +5 -0
- data/test/fixture/one/public/css/bar.css +0 -0
- data/test/fixture/one/public/css/style.css +1 -0
- data/test/fixture/one/public/hello.html +5 -0
- data/test/fixture/one/public/hi.html +1 -0
- data/test/fixture/one/public/images/bar.gif +0 -0
- data/test/fixture/one/public/images/baz.png +0 -0
- data/test/fixture/one/public/images/foo.jpg +0 -0
- data/test/fixture/one/public/index.html +7 -0
- data/test/fixture/one/site/about/index.scss +1 -0
- data/test/fixture/one/site/about/us.haml +3 -0
- data/test/fixture/one/site/cheers.html.haml +1 -0
- data/test/fixture/one/site/css/bar.scss +0 -0
- data/test/fixture/one/site/css/style.scss +2 -0
- data/test/fixture/one/site/hello.haml +3 -0
- data/test/fixture/one/site/hi.html +3 -0
- data/test/fixture/one/site/images/bar.gif +0 -0
- data/test/fixture/one/site/images/baz.png +0 -0
- data/test/fixture/one/site/images/foo.jpg +0 -0
- data/test/fixture/one/site/index.haml +7 -0
- data/test/fixture/parent/control/about/index.html +2 -0
- data/test/fixture/parent/control/about/us.html +2 -0
- data/test/fixture/parent/control/index.html +1 -0
- data/test/fixture/parent/hyde.conf +8 -0
- data/test/fixture/parent/site/about/index.haml +3 -0
- data/test/fixture/parent/site/about/us.haml +3 -0
- data/test/fixture/parent/site/index.haml +3 -0
- data/test/fixture/sort/control/about.html +6 -0
- data/test/fixture/sort/control/about/hardy.html +1 -0
- data/test/fixture/sort/control/about/intrepid.html +1 -0
- data/test/fixture/sort/hyde.conf +8 -0
- data/test/fixture/sort/site/about.haml +3 -0
- data/test/fixture/sort/site/about/hardy.haml +4 -0
- data/test/fixture/sort/site/about/intrepid.haml +4 -0
- data/test/fixture/subclass/control/index.html +1 -0
- data/test/fixture/subclass/extensions/a/a.rb +12 -0
- data/test/fixture/subclass/hyde.conf +9 -0
- data/test/fixture/subclass/layouts/default.haml +1 -0
- data/test/fixture/subclass/layouts/post.haml +1 -0
- data/test/fixture/subclass/site/index.haml +4 -0
- data/test/helper.rb +36 -0
- data/test/unit/build_options_test.rb +18 -0
- data/test/unit/extensions_test.rb +17 -0
- data/test/unit/fixture_test.rb +122 -0
- data/test/unit/page_test.rb +58 -0
- data/test/unit/proton_test.rb +27 -0
- data/test/unit/set_test.rb +26 -0
- metadata +301 -0
@@ -0,0 +1,176 @@
|
|
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]
|
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
|
+
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'cuba'
|
2
|
+
require 'rack'
|
3
|
+
require 'proton'
|
4
|
+
|
5
|
+
# Module: Proton::Server
|
6
|
+
# The Proton server rack application.
|
7
|
+
|
8
|
+
class Proton
|
9
|
+
Server = Cuba.dup
|
10
|
+
|
11
|
+
module Server; end
|
12
|
+
|
13
|
+
module Server::PageHelpers
|
14
|
+
def not_found
|
15
|
+
show_status nil
|
16
|
+
res.status = 404
|
17
|
+
res.write "<h1>File Not Found</h1><p>The path <code>#{env['PATH_INFO']}</code> was not found." + " "*1024
|
18
|
+
end
|
19
|
+
|
20
|
+
def options
|
21
|
+
@options ||= Hash.new
|
22
|
+
end
|
23
|
+
|
24
|
+
def show_status(page)
|
25
|
+
return if options[:quiet]
|
26
|
+
path = env['PATH_INFO']
|
27
|
+
return if path == '/favicon.ico'
|
28
|
+
|
29
|
+
status = page ? "\033[0;32m[ OK ]" : "\033[0;31m[404 ]"
|
30
|
+
verb = get ? 'GET ' : (post ? 'POST' : '')
|
31
|
+
puts "%s\033[0;m %s %s" % [ status, verb, env['PATH_INFO'] ]
|
32
|
+
puts " src: #{page.filepath} (#{page.tilt_engine_name})" if page && page.tilt?
|
33
|
+
end
|
34
|
+
|
35
|
+
def mime_type_for(page)
|
36
|
+
type = page.mime_type
|
37
|
+
type ||= Rack::Mime::MIME_TYPES[File.extname(page.file)]
|
38
|
+
type
|
39
|
+
end
|
40
|
+
|
41
|
+
def server
|
42
|
+
Proton::Server
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
module Proton::Server
|
47
|
+
Ron.send :include, PageHelpers
|
48
|
+
|
49
|
+
define do
|
50
|
+
on default do
|
51
|
+
begin
|
52
|
+
page = Proton::Page[env['PATH_INFO']] or break not_found
|
53
|
+
|
54
|
+
# Make the clients use If-Modified-Since
|
55
|
+
res['Cache-Control'] = 'max-age=86400, public, must-revalidate'
|
56
|
+
|
57
|
+
mtime = [server.options[:last_modified].to_i, File.mtime(page.file).to_i].compact.max
|
58
|
+
res['Last-Modified'] = mtime.to_s if mtime
|
59
|
+
|
60
|
+
# Get the MIME type from Proton, then fallback to Rack
|
61
|
+
type = mime_type_for(page)
|
62
|
+
res['Content-Type'] = type if type
|
63
|
+
|
64
|
+
# Okay, we're done
|
65
|
+
res.write page.to_html
|
66
|
+
show_status page
|
67
|
+
rescue => e
|
68
|
+
res['Content-Type'] = 'text/html'
|
69
|
+
res.write "<h1>#{e.class}: #{e.message}</h1><ul>#{e.backtrace.map{|l|"<li>#{l}</li>"}.join('')}</ul>"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
module Proton::Server
|
77
|
+
# Available options:
|
78
|
+
# :last_modified -- timestamp for all files
|
79
|
+
def self.options
|
80
|
+
@options ||= Hash.new
|
81
|
+
end
|
82
|
+
|
83
|
+
# :Host, :Port
|
84
|
+
def self.run!(options={})
|
85
|
+
self.options.merge options
|
86
|
+
handler = rack_handler or return false
|
87
|
+
handler.run self, options
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.rack_handler
|
91
|
+
%w(thin mongrel webrick).each do |svr|
|
92
|
+
begin
|
93
|
+
return Rack::Handler.get(svr)
|
94
|
+
rescue LoadError
|
95
|
+
rescue NameError
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
data/lib/proton/set.rb
ADDED
@@ -0,0 +1,32 @@
|
|
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
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
div a{color:red}
|
@@ -0,0 +1,18 @@
|
|
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
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
div { a { color: red; } }
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
<h1>hey</h1>
|
@@ -0,0 +1 @@
|
|
1
|
+
$extension_loaded = 'aoeu'
|
@@ -0,0 +1 @@
|
|
1
|
+
$hi = 1
|
@@ -0,0 +1 @@
|
|
1
|
+
%h1 hey
|
@@ -0,0 +1 @@
|
|
1
|
+
<h1>Yo</h1>
|
@@ -0,0 +1 @@
|
|
1
|
+
hyde_requirement: 9000.0
|
@@ -0,0 +1 @@
|
|
1
|
+
requirement: 9000.0
|