-
Notifications
You must be signed in to change notification settings - Fork 4
/
jekyll_models.rb
301 lines (264 loc) · 12.4 KB
/
jekyll_models.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
#------------------------------------------------------------------------
# encoding: utf-8
# @(#)jekyll_models.rb 1.00 20-Jun-2012 17:00
#
# Copyright (c) 2012 Kyle Paulsen. All Rights Reserved.
# Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php)
#
# Description: A generator that allows the user to make more jekyll objects
# like posts. It reads in YAML files from the specified directories
# and puts all of the information into the global site variable
# for easy access. It can also generate Model pages.
#
# Included filters : (none)
#
# Usage:
# Put jekyll_models.rb in your _plugins directory.
# Edit your _config.yml to have a jekyll_models property (For this example, I will set it
# to [projects, tests]
# Make the coorisponding model directories in the webroot. Don't forget the leading
# underscore (I made the dirs: _projects and _tests )
# Add the required templates to each directory:
# - the index.html template is assumed to be used for the list page of whatever model
# dir it is in. It must also be named index.html however it doesnt have to be
# generated that way (see the jekyll_models_urls setting)
# - the template.html template is used to help generate each model. It is sent the page
# var with model defined on it to represent the current generating model.
# So for example, in template.html I could do {{ page.model.name }}.
# template.html should be created with that exact name unless you are specifing
# a different template to use in every model YAML file. (see the template setting)
# Templates can also use YAML front matter!
# Make some model YAML files in the model directories. These files must end with:
# ( .txt or .yml or .yaml ) or else they will be ignored. These files are
# just plain old YAML files and can contain whatever you want.
# Generate your pages like normal! Your models will be generated and all the model objects
# will be attached to your global site var (like site.cars) for every page.
#
# Available _config.yml settings :
# - jekyll_models: Required! A list of the users' model types. These need matching
# directories with an underscore prefix under the web root.
# (Ex. jekyll_models: [Projects, Albums, Cars]
#
# - jekyll_models_generate_pages:
# Should JekyllModels generate model pages? (true | false)
# Default value: true
#
# - jekyll_models_urls: How Should JekyllModels organize generated models?
# rest-like = webroot.com/cars/jeep/index.html
# (with cars/index.html for the list page)
# models = webroot.com/cars/jeep.html
# (with cars/index.html for the list page)
# base = webroot.com/jeep.html
# (with webroot.com/cars.html for the list page)
# default: rest-like
#
# - site_base: The url of the webroot. (ex http://www.mydomain.com/ )
# If this is provided, JekyllModels can put each models'
# absolute url in "mdl_url" in its own object. This is for
# convenience when hyperlinking to models.
#
# Model Structure and Meaning:
# In each model YAML file, some properties can be set to customize behaviour.
# Other properties are automatically set. Here is a list of what's available:
#
# timestamp: You may set your own time to be sent in to jekyll like how
# posts have their time derived from their filename.
# This will be most usefull for sorting. YYYY-MM-DD is supported.
# If not specified, the YAML file modification date is used.
#
# mdl_name: This is automatically set by JekyllModels to match the YAML
# filename without the extension. This is used for generation.
#
# mdl_type: This is automatically set by JekyllModels to match the directory
# that the YAML file is in. (without the underscore prefix). This
# is used for generation.
#
# mdl_url: If site_base is defined in _config.yml then this will automatically
# be set to the absolute url of this model's generated page.
#
# template: You may specify what template this model should use to help
# generate it. For example, if you have the template "car_temp.html"
# then you can set this to "car_temp". Do not include ".html".
# By default, this is set to "template"
#
# Update History: (most recent first)
# 20-Jun-2012 kyle paulsen -- First public release.
#------------------------------------------------------------------------
module JekyllModels
# A class for reading in all the model YAML defs and putting them in the global site
# var for every page to see.
class ModelLoader
attr_accessor :config
def initialize(config)
if !config['jekyll_models']
puts "ModelLoader: there are no models defined in the _config.yml! Aborting!"
return
end
self.config = config
dirs = config['jekyll_models']
#make sure site base has a / on the end.
if self.config["site_base"]
if self.config["site_base"][-1,1] != "/"
self.config["site_base"] += "/"
end
end
#set default value for generating pages
self.config["jekyll_models_generate_pages"] = self.config["jekyll_models_generate_pages"] || "true"
#set default value for generation location style.
self.config["jekyll_models_urls"] = self.config["jekyll_models_urls"] || "rest-like"
#read in model YAML files...
dirs.each do |dir|
config[dir] = read_directory(dir, File.join(config['source'], "_"+dir))
end
end
def read_directory(mdl_name, dir)
models = []
entries = Dir.chdir(dir) { filter_entries(Dir.entries('.')) }
entries.each do |f|
f_abs = File.join(dir, f)
if !File.directory?(f_abs) && !File.symlink?(f_abs)
new_mdl = YAML.load_file(f_abs)
# set model data...
parts = f.split(".")
new_mdl["mdl_name"] = File.basename(f, "."+parts.last)
new_mdl["mdl_type"] = mdl_name
if new_mdl["timestamp"]
new_mdl["timestamp"] = new_mdl["timestamp"].to_time
else
new_mdl["timestamp"] = File.mtime(f_abs)
end
if self.config["site_base"]
new_mdl["mdl_url"] = self.config["site_base"]
new_mdl["mdl_url"] += case self.config['jekyll_models_urls']
when "rest-like"
"#{new_mdl["mdl_type"]}/#{new_mdl["mdl_name"]}"
when "models"
"#{new_mdl["mdl_type"]}/#{new_mdl["mdl_name"]}.html"
when "base"
"#{new_mdl["mdl_name"]}.html"
else
"#{new_mdl["mdl_type"]}/#{new_mdl["mdl_name"]}"
end
end
models << new_mdl
end
end
return models
end
def filter_entries(entries)
entries = entries.reject do |e|
ext = File.extname(e)
(ext != ".txt" && ext != ".yml" && ext != ".yaml") ||
['.', '_', '#'].include?(e[0..0]) ||
e[-1..-1] == '~' ||
File.symlink?(e)
end
end
end
# Pretty much this entire class was borrowed from Jim Pravetz's product_generator plugin.
# I found his blog here: http://jimpravetz.com/blog/2011/12/generating-jekyll-pages-from-data/
# He is awesome for putting his code up on the web.
class ModelPage < ::Jekyll::Page
# The resultant relative URL of where the published file will end up
# Added for use by a sitemap generator
attr_accessor :dest_url
# The last modified date to be used for web caching of this file.
# Derived from latest date of products.json and template files
# Added for use by a sitemap generator
attr_accessor :src_mtime
# Initialize a new Page.
#
# site - The Site object.
# base - The String path to the source.
# dest_dir - The String path between the dest and the file.
# dest_name - The String name of the destination file (e.g. index.html or myproduct.html)
# src_dir - The String path between the source and the file.
# src_name - The String filename of the source page file
# data_mtime - mtime of the products.json data file, used for sitemap generator
def initialize(site, base, dest_dir, dest_name, src_dir, src_name, data_mtime )
@site = site
@base = base
@dir = dest_dir
@dest_dir = dest_dir
@dest_name = dest_name
@dest_url = File.join( '/', dest_dir )
@src_mtime = data_mtime
src_name_with_ext = File.join(base, src_dir, src_name)
@name = src_name_with_ext
self.process(src_name_with_ext)
# Read the YAML from the specified page
self.read_yaml(File.join(base, src_dir), src_name )
# Remember the mod time, used for site_map
file_mtime = File.mtime( File.join(base, src_dir, src_name) )
@src_mtime = file_mtime if file_mtime > @src_mtime
end
# Override to set url properly
def to_liquid
self.data.deep_merge({
"url" => @dest_url,
"content" => self.content })
end
# Override so that we can control where the destination file goes
def destination(dest)
# The url needs to be unescaped in order to preserve the correct filename.
path = File.join(dest, @dest_dir, @dest_name )
path = File.join(path, "index.html") if self.url =~ /\/$/
path
end
end
class ::Jekyll::ModelGenerator < ::Jekyll::Generator
safe true
def initialize(config)
#start loadin those YAML files now!
ModelLoader.new(config)
end
def generate(site)
if site.config['jekyll_models_generate_pages'] && site.config['jekyll_models']
puts "ModelLoader: Building model pages!"
mdls = site.config['jekyll_models']
mdls.each do |mdl|
write_model_index(site, mdl)
write_model_instance_indexes(site, mdl)
end
end
end
#writes the list page for this model type
def write_model_index(site, model_name)
case site.config["jekyll_models_urls"]
when "base"
index = ModelPage.new(site, site.config['source'], "", model_name+'.html', "_"+model_name, 'index.html', Time.parse("1900-01-01"))
else
index = ModelPage.new(site, site.config['source'], model_name, 'index.html', "_"+model_name, 'index.html', Time.parse("1900-01-01"))
end
index.render(site.layouts, site.site_payload)
index.write(site.dest)
# Record the fact that this page has been added, otherwise Site::cleanup will remove it.
site.pages << index
end
#writes each model page and sends in the model through page.model
def write_model_instance_indexes(site, model_name)
models = site.config[model_name]
models.each do |mdl|
template_file = 'template.html'
if mdl['template']
template_file = mdl['template'] + ".html"
end
case site.config["jekyll_models_urls"]
when "rest-like"
index = ModelPage.new(site, site.config['source'], File.join(model_name, mdl['mdl_name']), 'index.html', "_"+model_name, template_file, mdl['timestamp'])
when "models"
index = ModelPage.new(site, site.config['source'], model_name, mdl['mdl_name']+'.html', "_"+model_name, template_file, mdl['timestamp'])
when "base"
index = ModelPage.new(site, site.config['source'], "", mdl['mdl_name']+'.html', "_"+model_name, template_file, mdl['timestamp'])
else
index = ModelPage.new(site, site.config['source'], File.join(model_name, mdl['mdl_name']), 'index.html', "_"+model_name, template_file, mdl['timestamp'])
end
index.data['model'] = mdl
index.render(site.layouts, site.site_payload)
index.write(site.dest)
# Record the fact that this page has been added, otherwise Site::cleanup will remove it.
site.pages << index
end
end
end
end