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,20 @@
|
|
|
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
|
data/lib/proton/meta.rb
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
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
|
data/lib/proton/page.rb
ADDED
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
class Proton
|
|
2
|
+
# A project.
|
|
3
|
+
#
|
|
4
|
+
# Getting pages from paths:
|
|
5
|
+
#
|
|
6
|
+
# # Feed it a URL path, not a filename.
|
|
7
|
+
# page = Proton::Page['/index.html'] # uses Proton.project
|
|
8
|
+
# page = Proton::Page['/index.html', project]
|
|
9
|
+
#
|
|
10
|
+
# Getting pages from files:
|
|
11
|
+
#
|
|
12
|
+
# # Feed it a file name, not a URL path.
|
|
13
|
+
# # Also, this does no sanity checks.
|
|
14
|
+
# page = Proton::Page.new('/home/rsc/index.html', project)
|
|
15
|
+
#
|
|
16
|
+
# page.exists?
|
|
17
|
+
# page.valid?
|
|
18
|
+
#
|
|
19
|
+
# Paths:
|
|
20
|
+
#
|
|
21
|
+
# page.filepath #=> "index.haml" -- path in the filesystem
|
|
22
|
+
# page.path #=> "/index.html" -- path as a RUL
|
|
23
|
+
#
|
|
24
|
+
# Meta:
|
|
25
|
+
#
|
|
26
|
+
# page.meta #=> OpenStruct of the metadata
|
|
27
|
+
# page.title #=> "Welcome to my site!"
|
|
28
|
+
#
|
|
29
|
+
# page.layout # Proton::Layout or nil
|
|
30
|
+
# page.layout?
|
|
31
|
+
#
|
|
32
|
+
# Types:
|
|
33
|
+
#
|
|
34
|
+
# page.html?
|
|
35
|
+
# page.mime_type #=> "text/html" or nil -- only for tilt? == true
|
|
36
|
+
# page.default_ext #=> "html"
|
|
37
|
+
#
|
|
38
|
+
# Contents:
|
|
39
|
+
#
|
|
40
|
+
# page.to_html
|
|
41
|
+
# page.to_html(locals={})
|
|
42
|
+
# page.content
|
|
43
|
+
# page.markup
|
|
44
|
+
#
|
|
45
|
+
# Traversion:
|
|
46
|
+
#
|
|
47
|
+
#
|
|
48
|
+
# # Pages (a Proton::Page or nil)
|
|
49
|
+
# page.parent
|
|
50
|
+
# page.next
|
|
51
|
+
#
|
|
52
|
+
# # Sets (a Proton::Set)
|
|
53
|
+
# page.children
|
|
54
|
+
# page.siblings
|
|
55
|
+
# page.breadcrumbs
|
|
56
|
+
#
|
|
57
|
+
# # Misc
|
|
58
|
+
# page.index? # if it's an index.html
|
|
59
|
+
# page.parent?
|
|
60
|
+
# page.root? # true if no parents
|
|
61
|
+
# page.depth
|
|
62
|
+
#
|
|
63
|
+
# Tilt:
|
|
64
|
+
#
|
|
65
|
+
# page.tilt? # true, if it's a dynamic file
|
|
66
|
+
# page.tilt_engine_name #=> 'RedCloth'
|
|
67
|
+
#
|
|
68
|
+
# Building:
|
|
69
|
+
#
|
|
70
|
+
# page.write
|
|
71
|
+
# page.write('~/foo.html')
|
|
72
|
+
#
|
|
73
|
+
class Page
|
|
74
|
+
attr_reader :project
|
|
75
|
+
attr_reader :file
|
|
76
|
+
|
|
77
|
+
def self.[](id, project=Proton.project)
|
|
78
|
+
site_path = root_path(project)
|
|
79
|
+
return nil if site_path.nil?
|
|
80
|
+
|
|
81
|
+
site = lambda { |*x| File.join site_path, *(x.compact) }
|
|
82
|
+
try = lambda { |_id| p = new(_id, project); p if p.exists? }
|
|
83
|
+
|
|
84
|
+
# For paths like '/' or '/hello/'
|
|
85
|
+
nonfile = File.basename(id).gsub('/','').empty?
|
|
86
|
+
|
|
87
|
+
# Account for:
|
|
88
|
+
# ~/mysite/site/about/us.html.haml
|
|
89
|
+
# about/us.html.haml => ~/mysite/site/about/us.html.haml
|
|
90
|
+
# about/us.html => ~/mysite/site/about/us.html.*
|
|
91
|
+
# about/us.html => ~/mysite/site/about/us.*
|
|
92
|
+
# about/us => ~/mysite/site/about/us/index.*
|
|
93
|
+
#
|
|
94
|
+
page = try[id]
|
|
95
|
+
page ||= try[site[id]]
|
|
96
|
+
unless nonfile
|
|
97
|
+
page ||= try[Dir[site["#{id}.*"]].first]
|
|
98
|
+
page ||= try[Dir[site["#{id.to_s.sub(/\.[^\.]*/,'')}.*"]].first]
|
|
99
|
+
end
|
|
100
|
+
page ||= try[Dir[site[id, "index.*"]].first]
|
|
101
|
+
|
|
102
|
+
# Subclass
|
|
103
|
+
if page && page.tilt? && page.meta[:type]
|
|
104
|
+
klass = Page.get_type(page.meta[:type])
|
|
105
|
+
raise Error, "#{page.filepath}: Class for type '#{page.meta[:type]}' not found" unless klass
|
|
106
|
+
page = klass.new(id, project)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
page
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def initialize(file, project=Proton.project)
|
|
113
|
+
@file = File.expand_path(file) if file.is_a?(String)
|
|
114
|
+
@project = project
|
|
115
|
+
raise Error if project.nil?
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Returns the URL path for a page.
|
|
119
|
+
def path
|
|
120
|
+
path = @file.sub(File.expand_path(root_path), '')
|
|
121
|
+
|
|
122
|
+
# if xx.haml (but not xx.html.haml),
|
|
123
|
+
if tilt?
|
|
124
|
+
path = path.sub(/\.[^\.]*$/, "")
|
|
125
|
+
path += ".#{default_ext}" unless File.basename(path).include?('.')
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
path
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Returns a short filepath relative to the project path
|
|
132
|
+
def filepath
|
|
133
|
+
root = project.root
|
|
134
|
+
fpath = file
|
|
135
|
+
fpath = fpath[root.size..-1] if fpath[0...root.size] == root
|
|
136
|
+
fpath
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def title
|
|
140
|
+
(meta.title if tilt?) || path
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
alias to_s title
|
|
144
|
+
|
|
145
|
+
def position
|
|
146
|
+
meta[:position] || title
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def <=>(other)
|
|
150
|
+
result = self.position <=> other.position
|
|
151
|
+
result ||= self.position.to_s <=> other.position.to_s
|
|
152
|
+
result
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Method: html? (Proton::Page)
|
|
156
|
+
# Returns true if the page is an HTML page.
|
|
157
|
+
|
|
158
|
+
def html?
|
|
159
|
+
mime_type == 'text/html'
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Method: mime_type (Proton::Page)
|
|
163
|
+
# Returns a MIME type for the page, based on what template engine was used.
|
|
164
|
+
#
|
|
165
|
+
# ## Example
|
|
166
|
+
# Page['/style.css'].mime_type #=> 'text/css'
|
|
167
|
+
# Page['/index.html'].mime_type #=> 'text/html'
|
|
168
|
+
#
|
|
169
|
+
# ## See also
|
|
170
|
+
# - {Proton::Page::default_ext}
|
|
171
|
+
#
|
|
172
|
+
def mime_type
|
|
173
|
+
return nil unless tilt?
|
|
174
|
+
|
|
175
|
+
mime = nil
|
|
176
|
+
mime = tilt_engine.default_mime_type if tilt_engine.respond_to?(:default_mime_type)
|
|
177
|
+
|
|
178
|
+
mime ||= case tilt_engine.name
|
|
179
|
+
when 'Tilt::SassTemplate' then 'text/css'
|
|
180
|
+
when 'Tilt::ScssTemplate' then 'text/css'
|
|
181
|
+
when 'Tilt::LessTemplate' then 'text/css'
|
|
182
|
+
when 'Tilt::CoffeeScriptTemplate' then 'application/javascript'
|
|
183
|
+
when 'Tilt::NokogiriTemplate' then 'text/xml'
|
|
184
|
+
when 'Tilt::BuilderTemplate' then 'text/xml'
|
|
185
|
+
else 'text/html'
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# Method: default_ext (Proton::Page)
|
|
190
|
+
# Returns a default extension for the page based on the page's MIME type.
|
|
191
|
+
#
|
|
192
|
+
# ## Example
|
|
193
|
+
# Page['/style.css'].default_ext #=> 'css'
|
|
194
|
+
# Page['/index.html'].default_ext #=> 'html'
|
|
195
|
+
#
|
|
196
|
+
# ## See also
|
|
197
|
+
# - {Proton::Page::mime_type}
|
|
198
|
+
|
|
199
|
+
def default_ext
|
|
200
|
+
case mime_type
|
|
201
|
+
when 'text/html' then 'html'
|
|
202
|
+
when 'text/css' then 'css'
|
|
203
|
+
when 'text/xml' then 'xml'
|
|
204
|
+
when 'application/javascript' then 'js'
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# Method: get_type (Proton::Page)
|
|
209
|
+
# Returns a page subtype.
|
|
210
|
+
#
|
|
211
|
+
# ## Example
|
|
212
|
+
# Page.get_type('post') => Proton::Page::Post
|
|
213
|
+
|
|
214
|
+
def self.get_type(type)
|
|
215
|
+
type = type.to_s
|
|
216
|
+
klass = type[0..0].upcase + type[1..-1].downcase
|
|
217
|
+
klass = klass.to_sym
|
|
218
|
+
self.const_get(klass) if self.const_defined?(klass)
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def exists?
|
|
222
|
+
@file and File.file?(@file||'') and valid?
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# Make sure that it's in the right folder.
|
|
226
|
+
def valid?
|
|
227
|
+
prefix = File.expand_path(root_path)
|
|
228
|
+
prefix == File.expand_path(@file)[0...prefix.size]
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def content(locals={}, tilt_options={}, &blk)
|
|
232
|
+
return markup unless tilt?
|
|
233
|
+
tilt(tilt_options).render(dup.extend(Helpers), locals, &blk)
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def to_html(locals={}, tilt_options={}, &blk)
|
|
237
|
+
html = content(locals, tilt_options, &blk)
|
|
238
|
+
html = layout.to_html(locals, tilt_options) { html } if layout?
|
|
239
|
+
html
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def layout
|
|
243
|
+
layout = meta.layout
|
|
244
|
+
layout ||= default_layout unless meta.layout == false
|
|
245
|
+
Layout[layout, page] if layout
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
def page
|
|
249
|
+
self
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def layout?
|
|
253
|
+
!! layout
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def meta
|
|
257
|
+
@meta ||= Meta.new(parts.first)
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
# Writes to the given output file.
|
|
261
|
+
def write(out=nil)
|
|
262
|
+
out ||= project.path(:output, path)
|
|
263
|
+
FileUtils.mkdir_p File.dirname(out)
|
|
264
|
+
|
|
265
|
+
if tilt?
|
|
266
|
+
File.open(out, 'w') { |f| f.write to_html({}, :build => true) }
|
|
267
|
+
else
|
|
268
|
+
FileUtils.cp file, out
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# Checks if the file is supported by tilt.
|
|
273
|
+
def tilt?
|
|
274
|
+
!! tilt_engine
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
# Returns the Tilt engine (eg Tilt::HamlEngine).
|
|
278
|
+
def tilt_engine
|
|
279
|
+
Tilt[@file]
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
def tilt_engine_name
|
|
283
|
+
tilt_engine.name.match(/:([^:]*)(?:Template?)$/)[1]
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
# Returns the tilt layout.
|
|
287
|
+
def tilt(tilt_options={})
|
|
288
|
+
if tilt?
|
|
289
|
+
parts
|
|
290
|
+
# HAML options and such (like :escape_html)
|
|
291
|
+
options = project.config.tilt_options_for(@file, tilt_options)
|
|
292
|
+
offset = @offset || 1
|
|
293
|
+
Tilt.new(@file, offset, options) { markup }
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def markup
|
|
298
|
+
parts.last
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
def method_missing(meth, *args, &blk)
|
|
302
|
+
super unless meta.instance_variable_get(:@table).keys.include?(meth.to_sym)
|
|
303
|
+
meta.send(meth)
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
def parent
|
|
307
|
+
parts = path.split('/') # ['', 'about', 'index.html']
|
|
308
|
+
|
|
309
|
+
try = lambda { |newpath| p = self.class[newpath, project]; p if p && p.path != path }
|
|
310
|
+
|
|
311
|
+
# Absolute root
|
|
312
|
+
return nil if index? and parts.size <= 2
|
|
313
|
+
|
|
314
|
+
parent = try[parts[0...-1].join('/')] # ['','about'] => '/about'
|
|
315
|
+
parent ||= try['/'] # Home
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
def children
|
|
319
|
+
files = if index?
|
|
320
|
+
# about/index.html => about/*
|
|
321
|
+
File.expand_path('../*', @file)
|
|
322
|
+
else
|
|
323
|
+
# products.html => products/*
|
|
324
|
+
base = File.basename(@file, '.*')
|
|
325
|
+
File.expand_path("../#{base}/*", @file)
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
Set.new Dir[files].
|
|
329
|
+
reject { |f| f == @file || project.ignored_files.include?(f) }.
|
|
330
|
+
map { |f| self.class[f, project] }.
|
|
331
|
+
compact.sort
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
def siblings
|
|
335
|
+
pages = (p = parent and p.children)
|
|
336
|
+
return Set.new unless pages
|
|
337
|
+
return Set.new unless pages.include?(self)
|
|
338
|
+
Set.new(pages)
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
def breadcrumbs
|
|
342
|
+
Set.new(parent? ? (parent.breadcrumbs + [self]) : [self])
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
def index?
|
|
346
|
+
File.basename(path, '.*') == 'index'
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
# Method: parent? (Proton::Page)
|
|
350
|
+
# Returns true if the page has a parent.
|
|
351
|
+
#
|
|
352
|
+
# This is the opposite of {Proton::Page::root?}.
|
|
353
|
+
#
|
|
354
|
+
# ## See also
|
|
355
|
+
# - {Proton::Page::root?}
|
|
356
|
+
|
|
357
|
+
def parent?
|
|
358
|
+
!parent.nil?
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
# Method: root? (Proton::Page)
|
|
362
|
+
# Returns true if the page is the home page.
|
|
363
|
+
#
|
|
364
|
+
# This is the opposite of {Proton::Page::parent?}.
|
|
365
|
+
#
|
|
366
|
+
# ## See also
|
|
367
|
+
# - {Proton::Page::parent?}
|
|
368
|
+
|
|
369
|
+
def root?
|
|
370
|
+
parent.nil?
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
def depth
|
|
374
|
+
breadcrumbs.size
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
def next
|
|
378
|
+
page = self
|
|
379
|
+
while true do
|
|
380
|
+
page.siblings.index(self)
|
|
381
|
+
end
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
def ==(other)
|
|
385
|
+
self.path == other.path
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
def inspect
|
|
389
|
+
"<##{self.class.name} #{path.inspect}>"
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
protected
|
|
393
|
+
|
|
394
|
+
# Method: default_layout (Proton::Page)
|
|
395
|
+
# Returns the default layout.
|
|
396
|
+
#
|
|
397
|
+
# This method may be overridden by subclasses as needed.
|
|
398
|
+
|
|
399
|
+
def default_layout
|
|
400
|
+
'default' if html?
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
# Returns the two parts of the markup.
|
|
404
|
+
def parts
|
|
405
|
+
@parts ||= begin
|
|
406
|
+
t = File.open(@file).read
|
|
407
|
+
t = t.force_encoding('UTF-8') if t.respond_to?(:force_encoding)
|
|
408
|
+
m = t.match(/^(.*?)\n--+\n(.*)$/m)
|
|
409
|
+
|
|
410
|
+
if m.nil?
|
|
411
|
+
[{}, t]
|
|
412
|
+
else
|
|
413
|
+
@offset = m[1].count("\n") + 2
|
|
414
|
+
data = YAML::load(m[1])
|
|
415
|
+
raise ArgumentError unless data.is_a?(Hash)
|
|
416
|
+
[data, m[2]]
|
|
417
|
+
end
|
|
418
|
+
rescue ArgumentError
|
|
419
|
+
[{}, t]
|
|
420
|
+
end
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
def self.root_path(project, *a)
|
|
424
|
+
project.path(:site, *a)
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
def root_path(*a)
|
|
428
|
+
self.class.root_path(project, *a)
|
|
429
|
+
end
|
|
430
|
+
end
|
|
431
|
+
end
|