serif 0.1.2 → 0.1.3
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/Gemfile.lock +3 -9
- data/README.md +61 -2
- data/lib/serif/config.rb +14 -0
- data/lib/serif/server.rb +10 -1
- data/lib/serif/site.rb +140 -6
- data/serif.gemspec +2 -2
- data/statics/skeleton/_config.yml +4 -0
- data/statics/skeleton/_drafts/sample-draft +3 -0
- data/statics/skeleton/_posts/2012-01-05-sample-post +4 -0
- data/statics/skeleton/_templates/archive_page.html +9 -0
- data/statics/skeleton/archive.html +7 -0
- metadata +11 -7
data/Gemfile.lock
CHANGED
@@ -1,26 +1,21 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
serif (0.1.
|
4
|
+
serif (0.1.2)
|
5
5
|
liquid (~> 2.4)
|
6
6
|
pygments.rb (~> 0.3)
|
7
7
|
rack (~> 1.0)
|
8
|
+
rack-rewrite (~> 1.3.0)
|
8
9
|
rake (~> 0.9)
|
9
10
|
redcarpet (~> 2.2)
|
10
11
|
redhead (~> 0.0.6)
|
11
12
|
sinatra (~> 1.3)
|
12
13
|
slop (~> 3.3)
|
13
|
-
yui-compressor
|
14
14
|
|
15
15
|
GEM
|
16
16
|
remote: http://rubygems.org/
|
17
17
|
specs:
|
18
|
-
POpen4 (0.1.4)
|
19
|
-
Platform (>= 0.4.0)
|
20
|
-
open4
|
21
|
-
Platform (0.4.0)
|
22
18
|
liquid (2.4.1)
|
23
|
-
open4 (1.3.0)
|
24
19
|
posix-spawn (0.3.6)
|
25
20
|
pygments.rb (0.3.2)
|
26
21
|
posix-spawn (~> 0.3.6)
|
@@ -28,6 +23,7 @@ GEM
|
|
28
23
|
rack (1.4.1)
|
29
24
|
rack-protection (1.2.0)
|
30
25
|
rack
|
26
|
+
rack-rewrite (1.3.1)
|
31
27
|
rake (0.9.2.2)
|
32
28
|
redcarpet (2.2.2)
|
33
29
|
redhead (0.0.6)
|
@@ -38,8 +34,6 @@ GEM
|
|
38
34
|
slop (3.3.3)
|
39
35
|
tilt (1.3.3)
|
40
36
|
yajl-ruby (1.1.0)
|
41
|
-
yui-compressor (0.9.6)
|
42
|
-
POpen4 (>= 0.1.4)
|
43
37
|
|
44
38
|
PLATFORMS
|
45
39
|
ruby
|
data/README.md
CHANGED
@@ -95,7 +95,8 @@ The structure of a Serif site is something like this:
|
|
95
95
|
│ ├── 2012-02-28-another-post
|
96
96
|
│ └── 2012-03-30-and-a-third
|
97
97
|
├── _templates
|
98
|
-
│
|
98
|
+
│ ├─── post.html
|
99
|
+
│ └─── archive_page.html
|
99
100
|
├── _trash
|
100
101
|
├── _config.yml
|
101
102
|
├── css
|
@@ -147,7 +148,12 @@ The headers are similar to Jekyll's YAML front matter, but here there are no for
|
|
147
148
|
|
148
149
|
## `_templates`
|
149
150
|
|
150
|
-
|
151
|
+
Two templates are available:
|
152
|
+
|
153
|
+
* `post.html`, which will be used to render individual post pages.
|
154
|
+
* `archive_page.html`, which will be used to render individual archive pages.
|
155
|
+
|
156
|
+
Both must be valid Liquid templates.
|
151
157
|
|
152
158
|
## `_trash`
|
153
159
|
|
@@ -207,6 +213,59 @@ In both cases, the output is, of course:
|
|
207
213
|
|
208
214
|
If you have a file like `feed.xml` that you wish to _not_ be contained within a layout, specify `layout: none` in the header for the file.
|
209
215
|
|
216
|
+
# Archive pages
|
217
|
+
|
218
|
+
By default, archive pages are made available at `/archive/:year/month`, e.g., `/archive/2012/11`. Individual archive pages can be customised by editing the `_templates/archive_page.html` file, which is used for each month.
|
219
|
+
|
220
|
+
Within the `archive_page.html` template, you have access to the variables `month`, which is a Ruby Date instance, and `posts` for the posts within that month.
|
221
|
+
|
222
|
+
To disable archive pages, or configure the URL format, see the section on configuration.
|
223
|
+
|
224
|
+
## Linking to archive pages
|
225
|
+
|
226
|
+
To link to archive pages, there is a `site.archives` template variable available in all pages. The structure of `site.archives` is a nested map starting at years:
|
227
|
+
|
228
|
+
```
|
229
|
+
{
|
230
|
+
"posts" => [...],
|
231
|
+
"years" => [
|
232
|
+
{
|
233
|
+
"date" => Date.new(2012),
|
234
|
+
"posts" => [...],
|
235
|
+
"months" => [
|
236
|
+
{ "date" => Date.new(2012, 12), "archive_url" => "/archive/2012/12", "posts" => [...] },
|
237
|
+
{ "date" => Date.new(2012, 11), "archive_url" => "/archive/2012/11", "posts" => [...] },
|
238
|
+
...
|
239
|
+
]
|
240
|
+
}
|
241
|
+
]
|
242
|
+
}
|
243
|
+
```
|
244
|
+
|
245
|
+
Using `site.archives`, you can iterate over `years`, then iterate over `months` and use `archive_url` to link to the archive page for that given month within the year.
|
246
|
+
|
247
|
+
# Configuration
|
248
|
+
|
249
|
+
Configuration goes in `_config.yml` and must be valid YAML. Here's a sample configuration with available options:
|
250
|
+
|
251
|
+
```
|
252
|
+
admin:
|
253
|
+
username: myusername
|
254
|
+
password: mypassword
|
255
|
+
permalink: /posts/:title
|
256
|
+
archive:
|
257
|
+
enabled: yes
|
258
|
+
url_format: /archive/:year/:month
|
259
|
+
```
|
260
|
+
|
261
|
+
`admin` contains the credentials used when accessing the admin interface. This information is private, of course.
|
262
|
+
|
263
|
+
`permalink` is the URL format for individual post pages. The default permalink value is `/:title`. For an explanation of the format of permalinks, see above.
|
264
|
+
|
265
|
+
`archive` contains configuration options concerning archive pages. `enabled` can be used to toggle whether archive pages are generated. If set to `no` or `false`, no archive pages will be generated. By default, this value is `yes`.
|
266
|
+
|
267
|
+
The `archive` `url_format` configuration option is the format used for archive pages. The default value is `/archive/:year/:month`. **This must include both year and month.** Visiting, e.g., `/archive/2012/11` would render posts made in November 2012. See the section on archive pages above for more details.
|
268
|
+
|
210
269
|
# Deploying
|
211
270
|
|
212
271
|
To serve the site, set any web server to use `/path/to/site/directory/_site` as its root. *NOTE:* URLs generated in the site do not contain `.html` "extensions" by default, so you will need a rewrite rule. Here's an example rewrite for nginx:
|
data/lib/serif/config.rb
CHANGED
@@ -21,5 +21,19 @@ class Config
|
|
21
21
|
def permalink
|
22
22
|
yaml["permalink"] || "/:title"
|
23
23
|
end
|
24
|
+
|
25
|
+
def archive_enabled?
|
26
|
+
a = yaml["archive"]
|
27
|
+
|
28
|
+
if a
|
29
|
+
a["enabled"]
|
30
|
+
else
|
31
|
+
false
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def archive_url_format
|
36
|
+
(yaml["archive"] || {})["url_format"] || "/archive/:year/:month"
|
37
|
+
end
|
24
38
|
end
|
25
39
|
end
|
data/lib/serif/server.rb
CHANGED
@@ -13,7 +13,16 @@ class DevelopmentServer
|
|
13
13
|
|
14
14
|
# it seems Rack::Rewrite doesn't like public_folder files, so here we are
|
15
15
|
get "*" do
|
16
|
-
|
16
|
+
# attempt the exact name + an extension
|
17
|
+
file = Dir[File.expand_path("_site#{params[:splat].join("/")}.*")].first
|
18
|
+
|
19
|
+
# try index.html under the directory if it failed. useful for archive directory requests.
|
20
|
+
file ||= Dir[File.expand_path("_site#{params[:splat].join("/")}/index.html")].first
|
21
|
+
|
22
|
+
# make a naive assumption that there's a 404 file at 404.html
|
23
|
+
file ||= Dir[File.expand_path("_site/404.html")].first
|
24
|
+
|
25
|
+
File.read(file)
|
17
26
|
end
|
18
27
|
end
|
19
28
|
|
data/lib/serif/site.rb
CHANGED
@@ -19,6 +19,7 @@ else
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
+
module Serif
|
22
23
|
module Filters
|
23
24
|
def strip(input)
|
24
25
|
input.strip
|
@@ -36,8 +37,9 @@ module Filters
|
|
36
37
|
input.xmlschema
|
37
38
|
end
|
38
39
|
end
|
40
|
+
end
|
39
41
|
|
40
|
-
Liquid::Template.register_filter(Filters)
|
42
|
+
Liquid::Template.register_filter(Serif::Filters)
|
41
43
|
|
42
44
|
module Serif
|
43
45
|
class Site
|
@@ -49,8 +51,10 @@ class Site
|
|
49
51
|
@source_directory
|
50
52
|
end
|
51
53
|
|
54
|
+
# Returns all of the site's posts, in reverse chronological order
|
55
|
+
# by creation time.
|
52
56
|
def posts
|
53
|
-
Post.all(self)
|
57
|
+
Post.all(self).sort_by { |entry| entry.created }.reverse
|
54
58
|
end
|
55
59
|
|
56
60
|
def drafts
|
@@ -78,7 +82,97 @@ class Site
|
|
78
82
|
!%w[.html .xml].include?(File.extname(filename))
|
79
83
|
end
|
80
84
|
|
81
|
-
#
|
85
|
+
# Returns the relative archive URL for the given date,
|
86
|
+
# using the value of config.archive_url_format
|
87
|
+
def archive_url_for_date(date)
|
88
|
+
format = config.archive_url_format
|
89
|
+
|
90
|
+
parts = {
|
91
|
+
"year" => date.year.to_s,
|
92
|
+
"month" => date.month.to_s.rjust(2, "0")
|
93
|
+
}
|
94
|
+
|
95
|
+
output = format
|
96
|
+
|
97
|
+
parts.each do |placeholder, value|
|
98
|
+
output = output.gsub(Regexp.quote(":" + placeholder), value)
|
99
|
+
end
|
100
|
+
|
101
|
+
output
|
102
|
+
end
|
103
|
+
|
104
|
+
# Returns a nested hash with the following structure:
|
105
|
+
#
|
106
|
+
# {
|
107
|
+
# :posts => [],
|
108
|
+
# :years => [
|
109
|
+
# {
|
110
|
+
# :date => Date.new(2012),
|
111
|
+
# :posts => [],
|
112
|
+
# :months => [
|
113
|
+
# { :date => Date.new(2012, 12), :archive_url => "/archive/2012/12", :posts => [] },
|
114
|
+
# { :date => Date.new(2012, 11), :archive_url => "/archive/2012/11", :posts => [] },
|
115
|
+
# # ...
|
116
|
+
# ]
|
117
|
+
# },
|
118
|
+
#
|
119
|
+
# # ...
|
120
|
+
# ]
|
121
|
+
# }
|
122
|
+
def archives
|
123
|
+
h = {}
|
124
|
+
h[:posts] = posts
|
125
|
+
|
126
|
+
# group posts by Date instances for the first day of the year
|
127
|
+
year_groups = posts.group_by { |post| Date.new(post.created.year) }.to_a
|
128
|
+
|
129
|
+
# collect all elements as maps for the year start date and the posts in that year
|
130
|
+
year_groups.map! do |year_start_date, posts_by_year|
|
131
|
+
{
|
132
|
+
:date => year_start_date,
|
133
|
+
:posts => posts_by_year.sort_by { |post| post.created }
|
134
|
+
}
|
135
|
+
end
|
136
|
+
|
137
|
+
year_groups.sort_by! { |year_hash| year_hash[:date] }
|
138
|
+
year_groups.reverse!
|
139
|
+
|
140
|
+
year_groups.each do |year_hash|
|
141
|
+
year_posts = year_hash[:posts]
|
142
|
+
|
143
|
+
# group the posts in the year by month
|
144
|
+
month_groups = year_posts.group_by { |post| Date.new(post.created.year, post.created.month) }.to_a
|
145
|
+
|
146
|
+
# collect the elements as maps for the month start date and the posts in that month
|
147
|
+
month_groups.map! do |month_start_date, posts_by_month|
|
148
|
+
{
|
149
|
+
:date => month_start_date,
|
150
|
+
:posts => posts_by_month.sort_by { |post| post.created },
|
151
|
+
:archive_url => archive_url_for_date(month_start_date)
|
152
|
+
}
|
153
|
+
end
|
154
|
+
|
155
|
+
month_groups.sort_by! { |month_hash| month_hash[:date] }
|
156
|
+
month_groups.reverse!
|
157
|
+
|
158
|
+
# set the months for the current year
|
159
|
+
year_hash[:months] = month_groups
|
160
|
+
end
|
161
|
+
|
162
|
+
h[:years] = year_groups
|
163
|
+
|
164
|
+
# return the final hash
|
165
|
+
h
|
166
|
+
end
|
167
|
+
|
168
|
+
def to_liquid
|
169
|
+
{
|
170
|
+
"posts" => posts,
|
171
|
+
"latest_update_time" => latest_update_time,
|
172
|
+
"archive" => self.class.stringify_keys(archives)
|
173
|
+
}
|
174
|
+
end
|
175
|
+
|
82
176
|
def generate
|
83
177
|
FileUtils.cd(@source_directory)
|
84
178
|
|
@@ -88,7 +182,7 @@ class Site
|
|
88
182
|
files = Dir["**/*"].select { |f| f !~ /\A_/ && File.file?(f) }
|
89
183
|
|
90
184
|
layout = Liquid::Template.parse(File.read("_layouts/default.html"))
|
91
|
-
posts = self.posts
|
185
|
+
posts = self.posts
|
92
186
|
|
93
187
|
files.each do |path|
|
94
188
|
puts "Processing file: #{path}"
|
@@ -119,9 +213,9 @@ class Site
|
|
119
213
|
end
|
120
214
|
|
121
215
|
if layout_option == "none"
|
122
|
-
f.puts Liquid::Template.parse(file.to_s).render!("site" =>
|
216
|
+
f.puts Liquid::Template.parse(file.to_s).render!("site" => self)
|
123
217
|
else
|
124
|
-
f.puts layout.render!("page" => { "title" => [title].compact }, "content" => Liquid::Template.parse(file.to_s).render!("site" =>
|
218
|
+
f.puts layout.render!("page" => { "title" => [title].compact }, "content" => Liquid::Template.parse(file.to_s).render!("site" => self))
|
125
219
|
end
|
126
220
|
end
|
127
221
|
end
|
@@ -137,6 +231,8 @@ class Site
|
|
137
231
|
end
|
138
232
|
end
|
139
233
|
|
234
|
+
generate_archives(layout)
|
235
|
+
|
140
236
|
if Dir.exist?("_site")
|
141
237
|
FileUtils.mv("_site", "/tmp/_site.#{Time.now.strftime("%Y-%m-%d-%H-%M-%S")}")
|
142
238
|
end
|
@@ -144,5 +240,43 @@ class Site
|
|
144
240
|
FileUtils.mv("tmp/_site", ".") && FileUtils.rm_rf("tmp/_site")
|
145
241
|
FileUtils.rmdir("tmp")
|
146
242
|
end
|
243
|
+
|
244
|
+
private
|
245
|
+
|
246
|
+
# Uses config.archive_url_format to generate pages
|
247
|
+
# using the archive_page.html template.
|
248
|
+
def generate_archives(layout)
|
249
|
+
return unless config.archive_enabled?
|
250
|
+
|
251
|
+
template = Liquid::Template.parse(File.read("_templates/archive_page.html"))
|
252
|
+
|
253
|
+
months = posts.group_by { |post| Date.new(post.created.year, post.created.month) }
|
254
|
+
|
255
|
+
months.each do |month, posts|
|
256
|
+
archive_path = tmp_path(archive_url_for_date(month))
|
257
|
+
|
258
|
+
FileUtils.mkdir_p(archive_path)
|
259
|
+
|
260
|
+
File.open(File.join(archive_path, "index.html"), "w") do |f|
|
261
|
+
f.puts layout.render!("content" => template.render!("site" => self, "month" => month, "posts" => posts))
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
def self.stringify_keys(obj)
|
267
|
+
return obj unless obj.is_a?(Hash) || obj.is_a?(Array)
|
268
|
+
|
269
|
+
if obj.is_a?(Array)
|
270
|
+
return obj.map do |el|
|
271
|
+
stringify_keys(el)
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
result = {}
|
276
|
+
obj.each do |key, value|
|
277
|
+
result[key.to_s] = stringify_keys(value)
|
278
|
+
end
|
279
|
+
result
|
280
|
+
end
|
147
281
|
end
|
148
282
|
end
|
data/serif.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "serif"
|
3
|
-
s.version = "0.1.
|
3
|
+
s.version = "0.1.3"
|
4
4
|
s.authors = ["Adam Prescott"]
|
5
5
|
s.email = ["adam@aprescott.com"]
|
6
6
|
s.homepage = "https://github.com/aprescott/serif"
|
@@ -15,7 +15,7 @@ Gem::Specification.new do |s|
|
|
15
15
|
[
|
16
16
|
"rake", "~> 0.9",
|
17
17
|
"rack", "~> 1.0",
|
18
|
-
"
|
18
|
+
"rack-rewrite", "~> 1.3.0",
|
19
19
|
"redcarpet", "~> 2.2",
|
20
20
|
"pygments.rb", "~> 0.3",
|
21
21
|
"sinatra", "~> 1.3",
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: serif
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-11-
|
12
|
+
date: 2012-11-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -44,21 +44,21 @@ dependencies:
|
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: '1.0'
|
46
46
|
- !ruby/object:Gem::Dependency
|
47
|
-
name:
|
47
|
+
name: rack-rewrite
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|
49
49
|
none: false
|
50
50
|
requirements:
|
51
|
-
- -
|
51
|
+
- - ~>
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version:
|
53
|
+
version: 1.3.0
|
54
54
|
type: :runtime
|
55
55
|
prerelease: false
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
57
|
none: false
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ~>
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
61
|
+
version: 1.3.0
|
62
62
|
- !ruby/object:Gem::Dependency
|
63
63
|
name: redcarpet
|
64
64
|
requirement: !ruby/object:Gem::Requirement
|
@@ -179,9 +179,13 @@ files:
|
|
179
179
|
- statics/templates/admin/index.liquid
|
180
180
|
- statics/templates/admin/edit_post.liquid
|
181
181
|
- statics/skeleton/index.html
|
182
|
+
- statics/skeleton/_templates/archive_page.html
|
182
183
|
- statics/skeleton/_templates/post.html
|
184
|
+
- statics/skeleton/_drafts/sample-draft
|
183
185
|
- statics/skeleton/_config.yml
|
186
|
+
- statics/skeleton/_posts/2012-01-05-sample-post
|
184
187
|
- statics/skeleton/_layouts/default.html
|
188
|
+
- statics/skeleton/archive.html
|
185
189
|
- statics/assets/js/mousetrap.min.js
|
186
190
|
- statics/assets/js/jquery.autosize.js
|
187
191
|
- bin/serif
|