proton 0.3.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|