nesta 0.13.0 → 0.15.0
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.
- checksums.yaml +4 -4
- data/.github/workflows/tests.yml +1 -1
- data/.gitignore +1 -0
- data/{CHANGES → CHANGELOG.md} +117 -21
- data/Gemfile.lock +28 -26
- data/LICENSE +1 -1
- data/README.md +45 -31
- data/RELEASING.md +1 -1
- data/bin/nesta +4 -1
- data/lib/nesta/app.rb +1 -2
- data/lib/nesta/commands/build.rb +38 -0
- data/lib/nesta/commands/new.rb +2 -1
- data/lib/nesta/commands.rb +1 -0
- data/lib/nesta/config.rb +49 -75
- data/lib/nesta/config_file.rb +5 -1
- data/lib/nesta/helpers.rb +0 -5
- data/lib/nesta/models/file_model.rb +191 -0
- data/lib/nesta/models/menu.rb +67 -0
- data/lib/nesta/models/page.rb +167 -0
- data/lib/nesta/models.rb +3 -422
- data/lib/nesta/navigation.rb +0 -5
- data/lib/nesta/overrides.rb +32 -43
- data/lib/nesta/plugin.rb +0 -16
- data/lib/nesta/static/assets.rb +50 -0
- data/lib/nesta/static/html_file.rb +26 -0
- data/lib/nesta/static/site.rb +104 -0
- data/lib/nesta/version.rb +1 -1
- data/lib/nesta.rb +1 -3
- data/nesta.gemspec +5 -5
- data/templates/config/config.yml +28 -2
- data/templates/themes/README.md +1 -1
- data/templates/themes/views/master.sass +1 -1
- data/test/integration/atom_feed_test.rb +1 -1
- data/test/integration/commands/build_test.rb +53 -0
- data/test/integration/overrides_test.rb +1 -1
- data/test/integration/sitemap_test.rb +1 -1
- data/test/support/temporary_files.rb +1 -1
- data/test/support/test_configuration.rb +2 -4
- data/test/unit/config_test.rb +25 -94
- data/test/unit/static/assets_test.rb +56 -0
- data/test/unit/static/html_file_test.rb +41 -0
- data/test/unit/static/site_test.rb +104 -0
- data/views/atom.haml +2 -2
- data/views/comments.haml +2 -2
- data/views/footer.haml +1 -1
- data/views/header.haml +2 -3
- data/views/layout.haml +2 -2
- data/views/master.sass +1 -1
- data/views/mixins.sass +2 -2
- data/views/normalize.scss +0 -1
- data/views/sitemap.haml +1 -1
- metadata +42 -31
- /data/test/unit/{file_model_test.rb → models/file_model_test.rb} +0 -0
- /data/test/unit/{menu_test.rb → models/menu_test.rb} +0 -0
- /data/test/unit/{page_test.rb → models/page_test.rb} +0 -0
data/lib/nesta/models.rb
CHANGED
@@ -1,424 +1,5 @@
|
|
1
|
-
require 'time'
|
2
|
-
|
3
1
|
require 'rdiscount'
|
4
2
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
# Only one of the Markdown processors needs to be available, so we can
|
9
|
-
# safely ignore these load errors.
|
10
|
-
end
|
11
|
-
|
12
|
-
register_template_handler :MarukuTemplate, 'mdown', 'md'
|
13
|
-
register_template_handler :KramdownTemplate, 'mdown', 'md'
|
14
|
-
register_template_handler :BlueClothTemplate, 'mdown', 'md'
|
15
|
-
register_template_handler :RDiscountTemplate, 'mdown', 'md'
|
16
|
-
register_template_handler :RedcarpetTemplate, 'mdown', 'md'
|
17
|
-
|
18
|
-
module Nesta
|
19
|
-
class HeadingNotSet < RuntimeError; end
|
20
|
-
class LinkTextNotSet < RuntimeError; end
|
21
|
-
class MetadataParseError < RuntimeError; end
|
22
|
-
|
23
|
-
class FileModel
|
24
|
-
FORMATS = [:mdown, :md, :haml, :textile]
|
25
|
-
@@model_cache = {}
|
26
|
-
@@filename_cache = {}
|
27
|
-
|
28
|
-
attr_reader :filename, :mtime
|
29
|
-
|
30
|
-
class CaseInsensitiveHash < Hash
|
31
|
-
def [](key)
|
32
|
-
super(key.to_s.downcase)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def self.model_path(basename = nil)
|
37
|
-
Nesta::Config.content_path(basename)
|
38
|
-
end
|
39
|
-
|
40
|
-
def self.find_all
|
41
|
-
file_pattern = File.join(model_path, "**", "*.{#{FORMATS.join(',')}}")
|
42
|
-
Dir.glob(file_pattern).map do |path|
|
43
|
-
relative = path.sub("#{model_path}/", "")
|
44
|
-
load(relative.sub(/\.(#{FORMATS.join('|')})/, ""))
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def self.find_file_for_path(path)
|
49
|
-
if ! @@filename_cache.has_key?(path)
|
50
|
-
FORMATS.each do |format|
|
51
|
-
[path, File.join(path, 'index')].each do |basename|
|
52
|
-
filename = model_path("#{basename}.#{format}")
|
53
|
-
if File.exist?(filename)
|
54
|
-
@@filename_cache[path] = filename
|
55
|
-
break
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
@@filename_cache[path]
|
61
|
-
end
|
62
|
-
|
63
|
-
def self.needs_loading?(path, filename)
|
64
|
-
@@model_cache[path].nil? || File.mtime(filename) > @@model_cache[path].mtime
|
65
|
-
end
|
66
|
-
|
67
|
-
def self.load(path)
|
68
|
-
if (filename = find_file_for_path(path)) && needs_loading?(path, filename)
|
69
|
-
@@model_cache[path] = self.new(filename)
|
70
|
-
end
|
71
|
-
@@model_cache[path]
|
72
|
-
end
|
73
|
-
|
74
|
-
def self.purge_cache
|
75
|
-
@@model_cache = {}
|
76
|
-
@@filename_cache = {}
|
77
|
-
end
|
78
|
-
|
79
|
-
def initialize(filename)
|
80
|
-
@filename = filename
|
81
|
-
@format = filename.split('.').last.to_sym
|
82
|
-
if File.zero?(filename)
|
83
|
-
@metadata = {}
|
84
|
-
@markup = ''
|
85
|
-
else
|
86
|
-
@metadata, @markup = parse_file
|
87
|
-
end
|
88
|
-
@mtime = File.mtime(filename)
|
89
|
-
end
|
90
|
-
|
91
|
-
def ==(other)
|
92
|
-
other.respond_to?(:path) && (self.path == other.path)
|
93
|
-
end
|
94
|
-
|
95
|
-
def index_page?
|
96
|
-
@filename =~ /\/?index\.\w+$/
|
97
|
-
end
|
98
|
-
|
99
|
-
def abspath
|
100
|
-
file_path = @filename.sub(self.class.model_path, '')
|
101
|
-
if index_page?
|
102
|
-
File.dirname(file_path)
|
103
|
-
else
|
104
|
-
File.join(File.dirname(file_path), File.basename(file_path, '.*'))
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def path
|
109
|
-
abspath.sub(/^\//, '')
|
110
|
-
end
|
111
|
-
|
112
|
-
def permalink
|
113
|
-
File.basename(path)
|
114
|
-
end
|
115
|
-
|
116
|
-
def layout
|
117
|
-
(metadata('layout') || 'layout').to_sym
|
118
|
-
end
|
119
|
-
|
120
|
-
def template
|
121
|
-
(metadata('template') || 'page').to_sym
|
122
|
-
end
|
123
|
-
|
124
|
-
def to_html(scope = Object.new)
|
125
|
-
convert_to_html(@format, scope, markup)
|
126
|
-
end
|
127
|
-
|
128
|
-
def last_modified
|
129
|
-
@last_modified ||= File.stat(@filename).mtime
|
130
|
-
end
|
131
|
-
|
132
|
-
def description
|
133
|
-
metadata('description')
|
134
|
-
end
|
135
|
-
|
136
|
-
def keywords
|
137
|
-
metadata('keywords')
|
138
|
-
end
|
139
|
-
|
140
|
-
def metadata(key)
|
141
|
-
@metadata[key]
|
142
|
-
end
|
143
|
-
|
144
|
-
def flagged_as?(flag)
|
145
|
-
flags = metadata('flags')
|
146
|
-
flags && flags.split(',').map { |name| name.strip }.include?(flag)
|
147
|
-
end
|
148
|
-
|
149
|
-
def parse_metadata(first_paragraph)
|
150
|
-
is_metadata = first_paragraph.split("\n").first =~ /^[\w ]+:/
|
151
|
-
raise MetadataParseError unless is_metadata
|
152
|
-
metadata = CaseInsensitiveHash.new
|
153
|
-
first_paragraph.split("\n").each do |line|
|
154
|
-
key, value = line.split(/\s*:\s*/, 2)
|
155
|
-
next if value.nil?
|
156
|
-
metadata[key.downcase] = value.chomp
|
157
|
-
end
|
158
|
-
metadata
|
159
|
-
end
|
160
|
-
|
161
|
-
private
|
162
|
-
def markup
|
163
|
-
@markup
|
164
|
-
end
|
165
|
-
|
166
|
-
def parse_file
|
167
|
-
contents = File.open(@filename).read
|
168
|
-
rescue Errno::ENOENT
|
169
|
-
raise Sinatra::NotFound
|
170
|
-
else
|
171
|
-
first_paragraph, remaining = contents.split(/\r?\n\r?\n/, 2)
|
172
|
-
begin
|
173
|
-
return parse_metadata(first_paragraph), remaining
|
174
|
-
rescue MetadataParseError
|
175
|
-
return {}, contents
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
def add_p_tags_to_haml(text)
|
180
|
-
contains_tags = (text =~ /^\s*%/)
|
181
|
-
if contains_tags
|
182
|
-
text
|
183
|
-
else
|
184
|
-
text.split(/\r?\n/).inject('') do |accumulator, line|
|
185
|
-
accumulator << "%p #{line}\n"
|
186
|
-
end
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
|
-
def convert_to_html(format, scope, text)
|
191
|
-
text = add_p_tags_to_haml(text) if @format == :haml
|
192
|
-
template = Tilt[format].new { text }
|
193
|
-
template.render(scope)
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
class Page < FileModel
|
198
|
-
def self.model_path(basename = nil)
|
199
|
-
Nesta::Config.page_path(basename)
|
200
|
-
end
|
201
|
-
|
202
|
-
def self.find_by_path(path)
|
203
|
-
page = load(path)
|
204
|
-
page && page.hidden? ? nil : page
|
205
|
-
end
|
206
|
-
|
207
|
-
def self.find_all
|
208
|
-
super.select { |p| ! p.hidden? }
|
209
|
-
end
|
210
|
-
|
211
|
-
def self.find_articles
|
212
|
-
find_all.select do |page|
|
213
|
-
page.date && page.date < DateTime.now
|
214
|
-
end.sort { |x, y| y.date <=> x.date }
|
215
|
-
end
|
216
|
-
|
217
|
-
def draft?
|
218
|
-
flagged_as?('draft')
|
219
|
-
end
|
220
|
-
|
221
|
-
def hidden?
|
222
|
-
draft? && Nesta::App.production?
|
223
|
-
end
|
224
|
-
|
225
|
-
def heading
|
226
|
-
regex = case @format
|
227
|
-
when :mdown, :md
|
228
|
-
/^#\s*(.*?)(\s*#+|$)/
|
229
|
-
when :haml
|
230
|
-
/^\s*%h1\s+(.*)/
|
231
|
-
when :textile
|
232
|
-
/^\s*h1\.\s+(.*)/
|
233
|
-
end
|
234
|
-
markup =~ regex
|
235
|
-
Regexp.last_match(1) or raise HeadingNotSet, "#{abspath} needs a heading"
|
236
|
-
end
|
237
|
-
|
238
|
-
def link_text
|
239
|
-
metadata('link text') || heading
|
240
|
-
rescue HeadingNotSet
|
241
|
-
raise LinkTextNotSet, "Need to link to '#{abspath}' but can't get link text"
|
242
|
-
end
|
243
|
-
|
244
|
-
def title
|
245
|
-
metadata('title') || link_text
|
246
|
-
rescue LinkTextNotSet
|
247
|
-
return Nesta::Config.title if abspath == '/'
|
248
|
-
raise
|
249
|
-
end
|
250
|
-
|
251
|
-
def date(format = nil)
|
252
|
-
@date ||= if metadata("date")
|
253
|
-
if format == :xmlschema
|
254
|
-
Time.parse(metadata("date")).xmlschema
|
255
|
-
else
|
256
|
-
DateTime.parse(metadata("date"))
|
257
|
-
end
|
258
|
-
end
|
259
|
-
end
|
260
|
-
|
261
|
-
def atom_id
|
262
|
-
metadata('atom id')
|
263
|
-
end
|
264
|
-
|
265
|
-
def read_more
|
266
|
-
metadata('read more') || Nesta::Config.read_more
|
267
|
-
end
|
268
|
-
|
269
|
-
def summary
|
270
|
-
if summary_text = metadata("summary")
|
271
|
-
summary_text.gsub!('\n', "\n")
|
272
|
-
convert_to_html(@format, Object.new, summary_text)
|
273
|
-
end
|
274
|
-
end
|
275
|
-
|
276
|
-
def body_markup
|
277
|
-
case @format
|
278
|
-
when :mdown, :md
|
279
|
-
markup.sub(/^#[^#].*$\r?\n(\r?\n)?/, '')
|
280
|
-
when :haml
|
281
|
-
markup.sub(/^\s*%h1\s+.*$\r?\n(\r?\n)?/, '')
|
282
|
-
when :textile
|
283
|
-
markup.sub(/^\s*h1\.\s+.*$\r?\n(\r?\n)?/, '')
|
284
|
-
end
|
285
|
-
end
|
286
|
-
|
287
|
-
def body(scope = Object.new)
|
288
|
-
convert_to_html(@format, scope, body_markup)
|
289
|
-
end
|
290
|
-
|
291
|
-
def categories
|
292
|
-
paths = category_strings.map { |specifier| specifier.sub(/:-?\d+$/, '') }
|
293
|
-
valid_paths(paths).map { |p| Page.find_by_path(p) }
|
294
|
-
end
|
295
|
-
|
296
|
-
def priority(category)
|
297
|
-
category_string = category_strings.detect do |string|
|
298
|
-
string =~ /^#{category}([,:\s]|$)/
|
299
|
-
end
|
300
|
-
category_string && category_string.split(':', 2)[-1].to_i
|
301
|
-
end
|
302
|
-
|
303
|
-
def parent
|
304
|
-
if abspath == '/'
|
305
|
-
nil
|
306
|
-
else
|
307
|
-
parent_path = File.dirname(path)
|
308
|
-
while parent_path != '.' do
|
309
|
-
parent = Page.load(parent_path)
|
310
|
-
return parent unless parent.nil?
|
311
|
-
parent_path = File.dirname(parent_path)
|
312
|
-
end
|
313
|
-
return categories.first unless categories.empty?
|
314
|
-
Page.load('index')
|
315
|
-
end
|
316
|
-
end
|
317
|
-
|
318
|
-
def pages
|
319
|
-
in_category = Page.find_all.select do |page|
|
320
|
-
page.date.nil? && page.categories.include?(self)
|
321
|
-
end
|
322
|
-
in_category.sort do |x, y|
|
323
|
-
by_priority = y.priority(path) <=> x.priority(path)
|
324
|
-
if by_priority == 0
|
325
|
-
x.link_text.downcase <=> y.link_text.downcase
|
326
|
-
else
|
327
|
-
by_priority
|
328
|
-
end
|
329
|
-
end
|
330
|
-
end
|
331
|
-
|
332
|
-
def articles
|
333
|
-
Page.find_articles.select { |article| article.categories.include?(self) }
|
334
|
-
end
|
335
|
-
|
336
|
-
def receives_comments?
|
337
|
-
! date.nil?
|
338
|
-
end
|
339
|
-
|
340
|
-
private
|
341
|
-
def category_strings
|
342
|
-
strings = metadata('categories')
|
343
|
-
strings.nil? ? [] : strings.split(',').map { |string| string.strip }
|
344
|
-
end
|
345
|
-
|
346
|
-
def valid_paths(paths)
|
347
|
-
page_dir = Nesta::Config.page_path
|
348
|
-
paths.select do |path|
|
349
|
-
FORMATS.detect do |format|
|
350
|
-
[path, File.join(path, 'index')].detect do |candidate|
|
351
|
-
File.exist?(File.join(page_dir, "#{candidate}.#{format}"))
|
352
|
-
end
|
353
|
-
end
|
354
|
-
end
|
355
|
-
end
|
356
|
-
end
|
357
|
-
|
358
|
-
class Menu
|
359
|
-
INDENT = " " * 2
|
360
|
-
|
361
|
-
def self.full_menu
|
362
|
-
menu = []
|
363
|
-
menu_file = Nesta::Config.content_path('menu.txt')
|
364
|
-
if File.exist?(menu_file)
|
365
|
-
File.open(menu_file) { |file| append_menu_item(menu, file, 0) }
|
366
|
-
end
|
367
|
-
menu
|
368
|
-
end
|
369
|
-
|
370
|
-
def self.top_level
|
371
|
-
full_menu.reject { |item| item.is_a?(Array) }
|
372
|
-
end
|
373
|
-
|
374
|
-
def self.for_path(path)
|
375
|
-
path.sub!(Regexp.new('^/'), '')
|
376
|
-
if path.empty?
|
377
|
-
full_menu
|
378
|
-
else
|
379
|
-
find_menu_item_by_path(full_menu, path)
|
380
|
-
end
|
381
|
-
end
|
382
|
-
|
383
|
-
private
|
384
|
-
def self.append_menu_item(menu, file, depth)
|
385
|
-
path = file.readline
|
386
|
-
rescue EOFError
|
387
|
-
else
|
388
|
-
page = Page.load(path.strip)
|
389
|
-
current_depth = path.scan(INDENT).size
|
390
|
-
if page
|
391
|
-
if current_depth > depth
|
392
|
-
sub_menu_for_depth(menu, depth) << [page]
|
393
|
-
else
|
394
|
-
sub_menu_for_depth(menu, current_depth) << page
|
395
|
-
end
|
396
|
-
end
|
397
|
-
append_menu_item(menu, file, current_depth)
|
398
|
-
end
|
399
|
-
|
400
|
-
def self.sub_menu_for_depth(menu, depth)
|
401
|
-
sub_menu = menu
|
402
|
-
depth.times { sub_menu = sub_menu[-1] }
|
403
|
-
sub_menu
|
404
|
-
end
|
405
|
-
|
406
|
-
def self.find_menu_item_by_path(menu, path)
|
407
|
-
item = menu.detect do |item|
|
408
|
-
item.respond_to?(:path) && (item.path == path)
|
409
|
-
end
|
410
|
-
if item
|
411
|
-
subsequent = menu[menu.index(item) + 1]
|
412
|
-
item = [item]
|
413
|
-
item << subsequent if subsequent.respond_to?(:each)
|
414
|
-
else
|
415
|
-
sub_menus = menu.select { |menu_item| menu_item.respond_to?(:each) }
|
416
|
-
sub_menus.each do |sub_menu|
|
417
|
-
item = find_menu_item_by_path(sub_menu, path)
|
418
|
-
break if item
|
419
|
-
end
|
420
|
-
end
|
421
|
-
item
|
422
|
-
end
|
423
|
-
end
|
424
|
-
end
|
3
|
+
require_relative './models/file_model'
|
4
|
+
require_relative './models/menu'
|
5
|
+
require_relative './models/page'
|
data/lib/nesta/navigation.rb
CHANGED
data/lib/nesta/overrides.rb
CHANGED
@@ -1,30 +1,47 @@
|
|
1
1
|
module Nesta
|
2
2
|
module Overrides
|
3
3
|
module Renderers
|
4
|
-
def
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
4
|
+
def find_template(views, name, engine, &block)
|
5
|
+
user_paths = [
|
6
|
+
Nesta::Overrides.local_view_path,
|
7
|
+
Nesta::Overrides.theme_view_path,
|
8
|
+
views
|
9
|
+
].flatten.compact
|
10
|
+
user_paths.each do |path|
|
11
|
+
super(path, name, engine, &block)
|
12
|
+
end
|
12
13
|
end
|
13
14
|
|
14
15
|
def scss(template, options = {}, locals = {})
|
15
|
-
|
16
|
-
|
16
|
+
find_template(Nesta::App.settings.views, template, Tilt::ScssTemplate) do |file|
|
17
|
+
return Tilt.new(file).render if File.exist?(file)
|
18
|
+
end
|
19
|
+
raise IOError, "SCSS template not found: #{template}"
|
17
20
|
end
|
18
21
|
|
19
22
|
def sass(template, options = {}, locals = {})
|
20
|
-
|
21
|
-
|
23
|
+
find_template(Nesta::App.settings.views, template, Tilt::SassTemplate) do |file|
|
24
|
+
return Tilt.new(file).render if File.exist?(file)
|
25
|
+
end
|
26
|
+
raise IOError, "Sass template not found: #{template}"
|
22
27
|
end
|
23
28
|
|
24
29
|
def stylesheet(template, options = {}, locals = {})
|
25
|
-
|
26
|
-
|
27
|
-
|
30
|
+
scss(template, options, locals)
|
31
|
+
rescue IOError
|
32
|
+
sass(template, options, locals)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.local_view_path
|
37
|
+
Nesta::Path.local("views")
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.theme_view_path
|
41
|
+
if Nesta::Config.theme.nil?
|
42
|
+
nil
|
43
|
+
else
|
44
|
+
Nesta::Path.themes(Nesta::Config.theme, "views")
|
28
45
|
end
|
29
46
|
end
|
30
47
|
|
@@ -39,33 +56,5 @@ module Nesta
|
|
39
56
|
require app_file if File.exist?(app_file)
|
40
57
|
end
|
41
58
|
end
|
42
|
-
|
43
|
-
private
|
44
|
-
def self.template_exists?(engine, views, template)
|
45
|
-
views && File.exist?(File.join(views, "#{template}.#{engine}"))
|
46
|
-
end
|
47
|
-
|
48
|
-
def self.render_options(template, *engines)
|
49
|
-
[local_view_path, theme_view_path].each do |path|
|
50
|
-
engines.each do |engine|
|
51
|
-
if template_exists?(engine, path, template)
|
52
|
-
return { views: path }, engine
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
[{}, :sass]
|
57
|
-
end
|
58
|
-
|
59
|
-
def self.local_view_path
|
60
|
-
Nesta::Path.local("views")
|
61
|
-
end
|
62
|
-
|
63
|
-
def self.theme_view_path
|
64
|
-
if Nesta::Config.theme.nil?
|
65
|
-
nil
|
66
|
-
else
|
67
|
-
Nesta::Path.themes(Nesta::Config.theme, "views")
|
68
|
-
end
|
69
|
-
end
|
70
59
|
end
|
71
60
|
end
|
data/lib/nesta/plugin.rb
CHANGED
@@ -15,21 +15,5 @@ module Nesta
|
|
15
15
|
def self.initialize_plugins
|
16
16
|
self.loaded.each { |name| require "#{name}/init" }
|
17
17
|
end
|
18
|
-
|
19
|
-
def self.load_local_plugins
|
20
|
-
# This approach is deprecated; plugins should now be distributed
|
21
|
-
# as gems. See http://nestacms.com/docs/plugins/writing-plugins
|
22
|
-
plugins = Dir.glob(File.expand_path('../plugins/*', File.dirname(__FILE__)))
|
23
|
-
plugins.each { |path| require_local_plugin(path) }
|
24
|
-
end
|
25
|
-
|
26
|
-
def self.require_local_plugin(path)
|
27
|
-
Nesta.deprecated(
|
28
|
-
'loading plugins from ./plugins', "convert #{path} to a gem")
|
29
|
-
require File.join(path, 'lib', File.basename(path))
|
30
|
-
rescue LoadError => e
|
31
|
-
$stderr.write("Couldn't load plugins/#{File.basename(path)}: #{e}\n")
|
32
|
-
end
|
33
|
-
private_class_method :require_local_plugin
|
34
18
|
end
|
35
19
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'rake'
|
2
|
+
|
3
|
+
module Nesta
|
4
|
+
module Static
|
5
|
+
class Assets
|
6
|
+
def initialize(build_dir, logger = nil)
|
7
|
+
@build_dir = build_dir
|
8
|
+
@logger = logger
|
9
|
+
end
|
10
|
+
|
11
|
+
def copy_attachments
|
12
|
+
dest_basename = File.basename(Nesta::Config.attachment_path)
|
13
|
+
dest_dir = File.join(@build_dir, dest_basename)
|
14
|
+
copy_file_tree(Nesta::Config.attachment_path, dest_dir)
|
15
|
+
end
|
16
|
+
|
17
|
+
def copy_public_folder
|
18
|
+
copy_file_tree(Nesta::App.settings.public_folder, @build_dir)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def log(message)
|
24
|
+
@logger.call(message) if @logger
|
25
|
+
end
|
26
|
+
|
27
|
+
def copy_file_tree(source_dir, dest_dir)
|
28
|
+
files_in_tree(source_dir).each do |file|
|
29
|
+
target = File.join(dest_dir, file.sub(/^#{source_dir}\//, ''))
|
30
|
+
task = Rake::FileTask.define_task(target => file) do
|
31
|
+
target_dir = File.dirname(target)
|
32
|
+
FileUtils.mkdir_p(target_dir) unless Dir.exist?(target_dir)
|
33
|
+
FileUtils.cp(file, target_dir)
|
34
|
+
log("Copied #{file} to #{target}")
|
35
|
+
end
|
36
|
+
task.invoke
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def files_in_tree(directory)
|
41
|
+
Rake::FileList["#{directory}/**/*"].tap do |assets|
|
42
|
+
assets.exclude('~*')
|
43
|
+
assets.exclude do |f|
|
44
|
+
File.directory?(f)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Nesta
|
2
|
+
module Static
|
3
|
+
class HtmlFile
|
4
|
+
def initialize(build_dir, page)
|
5
|
+
@build_dir = build_dir
|
6
|
+
@content_path = page.filename
|
7
|
+
end
|
8
|
+
|
9
|
+
def page_shares_path_with_directory?(dir, base_without_ext)
|
10
|
+
Dir.exist?(File.join(dir, base_without_ext))
|
11
|
+
end
|
12
|
+
|
13
|
+
def filename
|
14
|
+
dir, base = File.split(@content_path)
|
15
|
+
base_without_ext = File.basename(base, File.extname(base))
|
16
|
+
subdir = dir.sub(/^#{Nesta::Config.page_path}/, '')
|
17
|
+
path = File.join(@build_dir, subdir, base_without_ext)
|
18
|
+
if page_shares_path_with_directory?(dir, base_without_ext)
|
19
|
+
File.join(path, 'index.html')
|
20
|
+
else
|
21
|
+
path + '.html'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|