archival 0.0.4 → 0.0.8
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/.rubocop.yml +1 -1
- data/Gemfile +1 -1
- data/archival.gemspec +6 -1
- data/bin/redcarpet +29 -0
- data/lib/archival/builder.rb +149 -59
- data/lib/archival/helper_server.rb +1 -1
- data/lib/archival/listen.rb +42 -24
- data/lib/archival/markdown_renderer.rb +33 -0
- data/lib/archival/parser.rb +33 -0
- data/lib/archival/template_array.rb +34 -0
- data/lib/archival/version.rb +1 -1
- data/lib/archival.rb +11 -0
- data/lib/tags/asset.rb +51 -0
- data/lib/tags/layout.rb +14 -5
- data/package.json +1 -1
- metadata +23 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6d3848687ae065595e19f5b75bb50927318e81df6d6b878541b2ef44138f9d31
|
4
|
+
data.tar.gz: 7a48ab3c689dcbb886f2441216750729ec892e40d6dc0a39197fba17eb9c4ab2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '039d5ae09373d249e90fd850e7bd68970ae5ad3c394ed452016e4acaca4df5063d1aab818a09f9a365af9e3277b777257c27d2c4cc365b7d8daafcb33842e8a3'
|
7
|
+
data.tar.gz: 6246274ed1209a20819616480c7a1ffde1422b1a68bf5e728a3b637e61ac8675e2bc8fafa8a003cedac455e11ca21e5f22ef9039de96d95f1fc5dcab0f93111b
|
data/.rubocop.yml
CHANGED
data/Gemfile
CHANGED
data/archival.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = 'archival'
|
5
|
-
s.version = '0.0.
|
5
|
+
s.version = '0.0.8'
|
6
6
|
s.summary = 'An incredibly simple CMS for durable websites'
|
7
7
|
s.description = 'https://jesseditson.com/the-simplest-cms-part-1'
|
8
8
|
s.authors = ['Jesse Ditson']
|
@@ -24,5 +24,10 @@ Gem::Specification.new do |s|
|
|
24
24
|
|
25
25
|
s.add_dependency 'liquid', '~> 5.1.0'
|
26
26
|
s.add_dependency 'listen', '~> 3.7.0'
|
27
|
+
s.add_dependency 'redcarpet', '~> 3.5.1'
|
27
28
|
s.add_dependency 'tomlrb', '~> 2.0.1'
|
29
|
+
|
30
|
+
s.metadata = {
|
31
|
+
'rubygems_mfa_required' => 'true'
|
32
|
+
}
|
28
33
|
end
|
data/bin/redcarpet
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'redcarpet' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("redcarpet", "redcarpet")
|
data/lib/archival/builder.rb
CHANGED
@@ -2,12 +2,12 @@
|
|
2
2
|
|
3
3
|
require 'liquid'
|
4
4
|
require 'tomlrb'
|
5
|
-
require '
|
6
|
-
|
7
|
-
Liquid::Template.error_mode = :strict
|
8
|
-
Liquid::Template.register_tag('layout', Layout)
|
5
|
+
require 'redcarpet'
|
9
6
|
|
10
7
|
module Archival
|
8
|
+
class DuplicateKeyError < StandardError
|
9
|
+
end
|
10
|
+
|
11
11
|
class Builder
|
12
12
|
attr_reader :page_templates
|
13
13
|
|
@@ -16,24 +16,31 @@ module Archival
|
|
16
16
|
refresh_config
|
17
17
|
end
|
18
18
|
|
19
|
+
def pages_dir
|
20
|
+
File.join(@config.root, @config.pages_dir)
|
21
|
+
end
|
22
|
+
|
23
|
+
def objects_dir
|
24
|
+
File.join(@config.root, @config.objects_dir)
|
25
|
+
end
|
26
|
+
|
19
27
|
def refresh_config
|
20
28
|
@file_system = Liquid::LocalFileSystem.new(
|
21
|
-
|
29
|
+
pages_dir, '%s.liquid'
|
22
30
|
)
|
23
|
-
@variables = {}
|
24
31
|
@object_types = {}
|
25
32
|
@page_templates = {}
|
33
|
+
@dynamic_types = Set.new
|
34
|
+
@dynamic_templates = {}
|
35
|
+
@parser = Archival::Parser.new(pages_dir)
|
26
36
|
|
27
|
-
Liquid::Template.file_system =
|
37
|
+
Liquid::Template.file_system = Liquid::LocalFileSystem.new(
|
38
|
+
pages_dir, '_%s.liquid'
|
39
|
+
)
|
28
40
|
|
29
|
-
objects_definition_file = File.join(@config.root,
|
30
|
-
'objects.toml')
|
31
|
-
if File.file? objects_definition_file
|
32
|
-
@object_types = read_toml(objects_definition_file)
|
33
|
-
end
|
41
|
+
@objects_definition_file = File.join(@config.root, 'objects.toml')
|
34
42
|
|
35
43
|
update_pages
|
36
|
-
update_objects
|
37
44
|
end
|
38
45
|
|
39
46
|
def full_rebuild
|
@@ -41,8 +48,46 @@ module Archival
|
|
41
48
|
refresh_config
|
42
49
|
end
|
43
50
|
|
44
|
-
def
|
45
|
-
|
51
|
+
def update_objects(_updated_objects = nil)
|
52
|
+
@object_types = {}
|
53
|
+
if File.file? @objects_definition_file
|
54
|
+
@object_types = Tomlrb.load_file(@objects_definition_file)
|
55
|
+
end
|
56
|
+
@dynamic_types = Set.new
|
57
|
+
@object_types.each do |_name, definition|
|
58
|
+
is_template = definition.key? 'template'
|
59
|
+
@dynamic_types << definition['template'] if is_template
|
60
|
+
end
|
61
|
+
# TODO: remove deleted dynamic pages
|
62
|
+
end
|
63
|
+
|
64
|
+
def update_pages(_updated_pages = nil, _updated_objects = nil)
|
65
|
+
update_objects
|
66
|
+
# TODO: remove deleted pages
|
67
|
+
do_update_pages(pages_dir)
|
68
|
+
end
|
69
|
+
|
70
|
+
def update_assets(changes)
|
71
|
+
changes.each do |change|
|
72
|
+
asset_path = File.join(@config.build_dir, change.path)
|
73
|
+
case change.type
|
74
|
+
when :removed
|
75
|
+
FileUtils.rm_rf asset_path
|
76
|
+
else
|
77
|
+
puts change.path
|
78
|
+
FileUtils.copy_entry File.join(@config.root, change.path), asset_path
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def dynamic?(file)
|
84
|
+
@dynamic_types.include? File.basename(file, '.liquid')
|
85
|
+
end
|
86
|
+
|
87
|
+
def template_for_page(template_file)
|
88
|
+
content = @file_system.read_template_file(template_file)
|
89
|
+
content += dev_mode_content if @config.dev_mode
|
90
|
+
Liquid::Template.parse(content)
|
46
91
|
end
|
47
92
|
|
48
93
|
def do_update_pages(dir, prefix = nil)
|
@@ -58,62 +103,96 @@ module Archival
|
|
58
103
|
add_prefix(entry))
|
59
104
|
end
|
60
105
|
elsif File.file? File.join(dir, entry)
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
template_file =
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
content = @file_system.read_template_file(template_file)
|
69
|
-
content += dev_mode_content if @config.dev_mode
|
70
|
-
@page_templates[add_prefix.call(page_name)] =
|
71
|
-
Liquid::Template.parse(content)
|
106
|
+
page_name = File.basename(entry, '.liquid')
|
107
|
+
template_file = add_prefix.call(page_name)
|
108
|
+
if dynamic? entry
|
109
|
+
@dynamic_templates[template_file] = template_for_page(template_file)
|
110
|
+
elsif entry.end_with?('.liquid') && !(entry.start_with? '_')
|
111
|
+
@page_templates[template_file] =
|
112
|
+
template_for_page(template_file)
|
72
113
|
end
|
73
114
|
end
|
74
115
|
end
|
75
116
|
end
|
76
117
|
|
77
|
-
def
|
78
|
-
|
79
|
-
|
118
|
+
def read_objects(type)
|
119
|
+
obj_dir = File.join(objects_dir, type)
|
120
|
+
return unless File.directory? obj_dir
|
121
|
+
|
122
|
+
Dir.foreach(obj_dir) do |file|
|
123
|
+
if file.end_with? '.toml'
|
124
|
+
object = Tomlrb.load_file(File.join(
|
125
|
+
obj_dir, file
|
126
|
+
))
|
127
|
+
object[:name] =
|
128
|
+
File.basename(file, '.toml')
|
129
|
+
yield object[:name], object
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def path_for_template(name, type)
|
135
|
+
Pathname.new(File.join(pages_dir, type, "#{name}.html"))
|
80
136
|
end
|
81
137
|
|
82
|
-
def
|
138
|
+
def objects_for_template(template_path)
|
83
139
|
objects = {}
|
84
|
-
@object_types.each do |
|
85
|
-
objects[
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
objects[name].push object
|
96
|
-
end
|
140
|
+
@object_types.each do |type, definition|
|
141
|
+
objects[type] = {}
|
142
|
+
is_dynamic = @dynamic_types.include? type
|
143
|
+
read_objects type do |name, object|
|
144
|
+
objects[type][name] = @parser.parse_object(
|
145
|
+
object, definition, template_path
|
146
|
+
)
|
147
|
+
if is_dynamic
|
148
|
+
path = path_for_template(name, type)
|
149
|
+
objects[type][name]['path'] =
|
150
|
+
path.relative_path_from(File.dirname(template_path)).to_s
|
97
151
|
end
|
98
152
|
end
|
99
|
-
objects[
|
100
|
-
(a['order'] || a[:name]).to_s <=> (b['order'] || b[:name]).to_s
|
101
|
-
end
|
153
|
+
objects[type] = sort_objects(objects[type])
|
102
154
|
end
|
103
|
-
|
155
|
+
objects
|
104
156
|
end
|
105
157
|
|
106
|
-
def
|
107
|
-
|
108
|
-
|
158
|
+
def sort_objects(objects)
|
159
|
+
# Sort by either 'order' key or object name, depending on what is
|
160
|
+
# available.
|
161
|
+
sorted_by_keys = objects.sort_by do |name, obj|
|
162
|
+
obj.key?('order') ? obj['order'].to_s : name
|
163
|
+
end
|
164
|
+
sorted_objects = Archival::TemplateArray.new
|
165
|
+
sorted_by_keys.each do |d|
|
166
|
+
raise DuplicateKeyError if sorted_objects.key?(d[0])
|
109
167
|
|
110
|
-
|
111
|
-
|
168
|
+
sorted_objects.push(d[1])
|
169
|
+
sorted_objects[d[0]] = d[1]
|
170
|
+
end
|
171
|
+
sorted_objects
|
112
172
|
end
|
113
173
|
|
114
174
|
def render(page)
|
175
|
+
dir = File.join(pages_dir, File.dirname(page))
|
115
176
|
template = @page_templates[page]
|
116
|
-
|
177
|
+
template_path = File.join(dir, page)
|
178
|
+
parsed_objects = objects_for_template(template_path)
|
179
|
+
template.render('objects' => parsed_objects,
|
180
|
+
'template_path' => template_path)
|
181
|
+
end
|
182
|
+
|
183
|
+
def render_dynamic(type, name)
|
184
|
+
dir = File.join(pages_dir, type)
|
185
|
+
template = @dynamic_templates[type]
|
186
|
+
template_path = File.join(dir, name)
|
187
|
+
parsed_objects = objects_for_template(template_path)
|
188
|
+
obj = parsed_objects[type][name]
|
189
|
+
vars = {}
|
190
|
+
.merge(
|
191
|
+
'objects' => parsed_objects,
|
192
|
+
'template_path' => template_path
|
193
|
+
)
|
194
|
+
.merge({ type => obj })
|
195
|
+
template.render(vars)
|
117
196
|
end
|
118
197
|
|
119
198
|
def write_all
|
@@ -122,18 +201,29 @@ module Archival
|
|
122
201
|
out_dir = File.join(@config.build_dir,
|
123
202
|
File.dirname(template))
|
124
203
|
Dir.mkdir(out_dir) unless File.exist? out_dir
|
125
|
-
out_path = File.join(
|
126
|
-
"#{template}.html")
|
204
|
+
out_path = File.join(out_dir, "#{template}.html")
|
127
205
|
File.open(out_path, 'w+') do |file|
|
128
206
|
file.write(render(template))
|
129
207
|
end
|
130
208
|
end
|
131
|
-
|
209
|
+
@dynamic_types.each do |type|
|
210
|
+
out_dir = File.join(@config.build_dir, type)
|
211
|
+
Dir.mkdir(out_dir) unless File.exist? out_dir
|
212
|
+
read_objects(type) do |name|
|
213
|
+
out_path = File.join(out_dir, "#{name}.html")
|
214
|
+
File.open(out_path, 'w+') do |file|
|
215
|
+
file.write(render_dynamic(type, name))
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
132
219
|
|
133
|
-
# in production, also copy all assets to the dist folder.
|
220
|
+
# in production (or init), also copy all assets to the dist folder.
|
221
|
+
# in dev, they will be copied as they change.
|
134
222
|
@config.assets_dirs.each do |asset_dir|
|
135
|
-
|
136
|
-
|
223
|
+
asset_path = File.join(@config.build_dir, asset_dir)
|
224
|
+
next if @config.dev_mode || !File.exist?(asset_path)
|
225
|
+
|
226
|
+
FileUtils.copy_entry File.join(@config.root, asset_dir), asset_path
|
137
227
|
end
|
138
228
|
end
|
139
229
|
|
data/lib/archival/listen.rb
CHANGED
@@ -4,6 +4,8 @@ require 'listen'
|
|
4
4
|
require 'pathname'
|
5
5
|
|
6
6
|
module Archival
|
7
|
+
Change = Struct.new(:path, :type)
|
8
|
+
|
7
9
|
def listen(config = {})
|
8
10
|
@config = Config.new(config.merge(dev_mode: true))
|
9
11
|
builder = Builder.new(@config)
|
@@ -13,21 +15,27 @@ module Archival
|
|
13
15
|
ignore = %r{/dist/}
|
14
16
|
listener = Listen.to(@config.root,
|
15
17
|
ignore: ignore) do |modified, added, removed|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
18
|
+
changes = {
|
19
|
+
pages: [],
|
20
|
+
objects: [],
|
21
|
+
assets: [],
|
22
|
+
layout: [],
|
23
|
+
config: []
|
24
|
+
}
|
25
|
+
add_change = lambda { |file, type|
|
26
|
+
c_type = change_type(file)
|
27
|
+
changes[c_type] << change(file, type) unless c_type == :none
|
28
|
+
}
|
29
|
+
added.each do |file|
|
30
|
+
add_change.call(file, :added)
|
31
|
+
end
|
32
|
+
modified.each do |file|
|
33
|
+
add_change.call(file, :modified)
|
28
34
|
end
|
29
|
-
|
30
|
-
|
35
|
+
removed.each do |file|
|
36
|
+
add_change.call(file, :removed)
|
37
|
+
end
|
38
|
+
@server.refresh_client if rebuild?(builder, changes)
|
31
39
|
end
|
32
40
|
listener.start
|
33
41
|
serve_helpers
|
@@ -45,6 +53,13 @@ module Archival
|
|
45
53
|
false
|
46
54
|
end
|
47
55
|
|
56
|
+
def change(file, type)
|
57
|
+
c = Change.new
|
58
|
+
c.path = Pathname.new(file).relative_path_from(@config.root)
|
59
|
+
c.type = type
|
60
|
+
c
|
61
|
+
end
|
62
|
+
|
48
63
|
def change_type(file)
|
49
64
|
# a page was modified, rebuild the pages.
|
50
65
|
return :pages if child?(File.join(@config.root, @config.pages_dir),
|
@@ -53,26 +68,29 @@ module Archival
|
|
53
68
|
return :objects if child?(File.join(@config.root, @config.objects_dir),
|
54
69
|
file)
|
55
70
|
|
56
|
-
#
|
71
|
+
# an asset was changed, which just means to copy or delete it
|
57
72
|
@config.assets_dirs.each do |dir|
|
58
73
|
return :assets if child?(File.join(@config.root, dir), file)
|
59
74
|
end
|
60
|
-
|
61
|
-
return :
|
75
|
+
# other special files
|
76
|
+
return :layout if child?(File.join(@config.root, 'layout'), file)
|
77
|
+
return :config if ['manifest.toml',
|
62
78
|
'objects.toml'].include? File.basename(file)
|
63
79
|
|
64
80
|
:none
|
65
81
|
end
|
66
82
|
|
67
|
-
def rebuild?(builder,
|
68
|
-
|
69
|
-
return false
|
70
|
-
end
|
83
|
+
def rebuild?(builder, changes)
|
84
|
+
return false if changes.values.all?(&:empty?)
|
71
85
|
|
72
86
|
Logger.benchmark('rebuilt') do
|
73
|
-
|
74
|
-
|
75
|
-
|
87
|
+
if changes[:pages].length || changes[:objects].length
|
88
|
+
builder.update_pages(changes[:pages], changes[:objects])
|
89
|
+
end
|
90
|
+
builder.update_assets(changes[:assets]) if changes[:assets].length
|
91
|
+
if changes[:assets].length || changes[:layouts] || changes[:config]
|
92
|
+
builder.full_rebuild
|
93
|
+
end
|
76
94
|
builder.write_all
|
77
95
|
end
|
78
96
|
true
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'redcarpet'
|
4
|
+
|
5
|
+
module Archival
|
6
|
+
class MarkdownRenderer < Redcarpet::Render::HTML
|
7
|
+
def autolink(link, _link_type, _opts)
|
8
|
+
# TODO: handle link_type?
|
9
|
+
"<a href=\"#{rewrite_link(link)}\">#{rewrite_link(link)}</a>"
|
10
|
+
end
|
11
|
+
|
12
|
+
def link(link, title, content)
|
13
|
+
"<a href=\"#{rewrite_link(link)}\" title=\"#{title}\">#{content}</a>"
|
14
|
+
end
|
15
|
+
|
16
|
+
def image(link, title, alt_text)
|
17
|
+
"<img src=\"#{rewrite_link(link)}\" \
|
18
|
+
title=\"#{title}\" alt=\"#{alt_text}\"/>"
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def rewrite_link(link)
|
24
|
+
if link.start_with?('http') || link.start_with?('mailto') ||
|
25
|
+
link.start_with?('www') || link.start_with?('/')
|
26
|
+
link
|
27
|
+
end
|
28
|
+
template_dir = File.dirname(@options[:template_file])
|
29
|
+
resolved_link = Pathname.new(File.join(@options[:pages_root], link))
|
30
|
+
resolved_link.relative_path_from(template_dir)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'liquid'
|
4
|
+
require 'redcarpet'
|
5
|
+
|
6
|
+
module Archival
|
7
|
+
class Parser
|
8
|
+
def initialize(pages_root)
|
9
|
+
@pages_root = pages_root
|
10
|
+
end
|
11
|
+
|
12
|
+
def parse_object(object, definition, template_file)
|
13
|
+
markdown = Redcarpet::Markdown.new(
|
14
|
+
Archival::MarkdownRenderer.new(prettify: true,
|
15
|
+
hard_wrap: true),
|
16
|
+
no_intra_emphasis: true,
|
17
|
+
fenced_code_blocks: true,
|
18
|
+
autolink: true,
|
19
|
+
strikethrough: true,
|
20
|
+
underline: true,
|
21
|
+
template_file: template_file,
|
22
|
+
pages_root: @pages_root
|
23
|
+
)
|
24
|
+
definition.each do |name, type|
|
25
|
+
case type
|
26
|
+
when 'markdown'
|
27
|
+
object[name] = markdown.render(object[name]) if object.key? name
|
28
|
+
end
|
29
|
+
end
|
30
|
+
object
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Archival
|
4
|
+
class TemplateArray < Array
|
5
|
+
alias subscript_access []
|
6
|
+
alias subscript_write []=
|
7
|
+
|
8
|
+
def initialize(*args)
|
9
|
+
super(*args)
|
10
|
+
@data = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def [](*args)
|
14
|
+
key = args[0]
|
15
|
+
return @data[key] if key.is_a? String
|
16
|
+
return @data[key] if key.is_a? Symbol
|
17
|
+
|
18
|
+
subscript_access(*args)
|
19
|
+
end
|
20
|
+
|
21
|
+
def []=(*args)
|
22
|
+
key = args[0]
|
23
|
+
if key.is_a?(String) || key.is_a?(Symbol)
|
24
|
+
@data[key] = args[1]
|
25
|
+
return
|
26
|
+
end
|
27
|
+
subscript_write(*args)
|
28
|
+
end
|
29
|
+
|
30
|
+
def key?(key)
|
31
|
+
@data.key?(key)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/archival/version.rb
CHANGED
data/lib/archival.rb
CHANGED
@@ -1,12 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'liquid'
|
4
|
+
require 'tags/layout'
|
5
|
+
require 'tags/asset'
|
6
|
+
|
3
7
|
module Archival
|
4
8
|
# Main Archival module. See https://archival.dev for docs.
|
5
9
|
end
|
6
10
|
|
11
|
+
Liquid::Template.error_mode = :strict
|
12
|
+
Liquid::Template.register_tag('layout', Layout)
|
13
|
+
Liquid::Template.register_tag('asset', Asset)
|
14
|
+
|
7
15
|
require 'archival/version'
|
16
|
+
require 'archival/template_array'
|
8
17
|
require 'archival/logger'
|
9
18
|
require 'archival/config'
|
19
|
+
require 'archival/markdown_renderer'
|
10
20
|
require 'archival/helper_server'
|
21
|
+
require 'archival/parser'
|
11
22
|
require 'archival/builder'
|
12
23
|
require 'archival/listen'
|
data/lib/tags/asset.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'liquid'
|
4
|
+
|
5
|
+
class Asset < Liquid::Tag
|
6
|
+
# Adds an `asset` tag to liquid. Usage:
|
7
|
+
#
|
8
|
+
# {% asset "path/to/asset.png" %}
|
9
|
+
#
|
10
|
+
# This will replace the tag with a relative path to the asset from the
|
11
|
+
# current template. Using normal tags will work from the root, but when
|
12
|
+
# building dynamic pages or reusing layouts, asset paths are dynamic and
|
13
|
+
# will need to be rewritten.
|
14
|
+
|
15
|
+
prepend Liquid::Tag::Disableable
|
16
|
+
|
17
|
+
SYNTAX = /(#{Liquid::QuotedFragment}+)/o.freeze
|
18
|
+
|
19
|
+
def initialize(tag_name, markup, tokens)
|
20
|
+
super
|
21
|
+
raise AssetError, 'Invalid layout syntax' unless markup =~ SYNTAX
|
22
|
+
|
23
|
+
@path = parse_expression(Regexp.last_match(1))
|
24
|
+
# This is defaulted to the pages dir, because it represents the structure
|
25
|
+
# of our website. Asset directories are copied as siblings at runtime.
|
26
|
+
@@root_dir ||= File.join(Dir.pwd, 'pages')
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.root_dir=(dir)
|
30
|
+
@@root_dir = dir
|
31
|
+
end
|
32
|
+
|
33
|
+
def render_to_output_buffer(context, output)
|
34
|
+
unless @@root_dir
|
35
|
+
raise AssetError,
|
36
|
+
'root_dir must be set on Archival::Asset'
|
37
|
+
end
|
38
|
+
|
39
|
+
unless context.key? 'template_path'
|
40
|
+
raise AssetError,
|
41
|
+
'template_path must be provided to parse when using assets'
|
42
|
+
end
|
43
|
+
template_path = File.dirname(context['template_path'])
|
44
|
+
abs_asset_path = Pathname.new(File.join(@@root_dir, @path))
|
45
|
+
output << abs_asset_path.relative_path_from(template_path).to_s
|
46
|
+
output
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class AssetError < Liquid::Error
|
51
|
+
end
|
data/lib/tags/layout.rb
CHANGED
@@ -25,7 +25,7 @@ class Layout < Liquid::Tag
|
|
25
25
|
super
|
26
26
|
|
27
27
|
@page_content = []
|
28
|
-
raise 'Invalid layout syntax' unless markup =~ SYNTAX
|
28
|
+
raise LayoutError, 'Invalid layout syntax' unless markup =~ SYNTAX
|
29
29
|
|
30
30
|
layout_name = Regexp.last_match(1)
|
31
31
|
@layout_name_expr = parse_expression(layout_name)
|
@@ -40,7 +40,9 @@ class Layout < Liquid::Tag
|
|
40
40
|
base_path = Dir.pwd
|
41
41
|
layout_dir = 'layout'
|
42
42
|
layout_path = File.join(base_path, layout_dir)
|
43
|
-
|
43
|
+
unless File.exist? layout_path
|
44
|
+
raise LayoutError, "Layout dir #{layout_path} not found"
|
45
|
+
end
|
44
46
|
|
45
47
|
layout_path
|
46
48
|
end
|
@@ -55,11 +57,15 @@ class Layout < Liquid::Tag
|
|
55
57
|
)
|
56
58
|
|
57
59
|
next unless File.basename(f, '.*') == layout_name
|
58
|
-
|
60
|
+
if found_layout
|
61
|
+
raise LayoutError, "More than one layout named #{layout_name} found."
|
62
|
+
end
|
59
63
|
|
60
64
|
found_layout = File.join(layout_path, f)
|
61
65
|
end
|
62
|
-
|
66
|
+
if found_layout.nil?
|
67
|
+
raise LayoutError, "No layouts named #{layout_name} found."
|
68
|
+
end
|
63
69
|
|
64
70
|
layout = File.read(found_layout)
|
65
71
|
@@layout_cache[layout_name] =
|
@@ -77,7 +83,7 @@ class Layout < Liquid::Tag
|
|
77
83
|
|
78
84
|
def render_to_output_buffer(context, output)
|
79
85
|
layout_name = context.evaluate(@layout_name_expr)
|
80
|
-
raise 'Bad layout name argument' unless layout_name
|
86
|
+
raise LayoutError, 'Bad layout name argument' unless layout_name
|
81
87
|
|
82
88
|
layout = load_layout(layout_name)
|
83
89
|
|
@@ -104,3 +110,6 @@ class Layout < Liquid::Tag
|
|
104
110
|
output
|
105
111
|
end
|
106
112
|
end
|
113
|
+
|
114
|
+
class LayoutError < Liquid::Error
|
115
|
+
end
|
data/package.json
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: archival
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jesse Ditson
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-11-
|
11
|
+
date: 2021-11-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: liquid
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 3.7.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: redcarpet
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 3.5.1
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 3.5.1
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: tomlrb
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -76,6 +90,7 @@ files:
|
|
76
90
|
- bin/ldiff
|
77
91
|
- bin/listen
|
78
92
|
- bin/rake
|
93
|
+
- bin/redcarpet
|
79
94
|
- bin/rspec
|
80
95
|
- bin/rubocop
|
81
96
|
- bin/ruby-parse
|
@@ -89,14 +104,19 @@ files:
|
|
89
104
|
- lib/archival/helper_server.rb
|
90
105
|
- lib/archival/listen.rb
|
91
106
|
- lib/archival/logger.rb
|
107
|
+
- lib/archival/markdown_renderer.rb
|
108
|
+
- lib/archival/parser.rb
|
92
109
|
- lib/archival/rake_tasks.rb
|
110
|
+
- lib/archival/template_array.rb
|
93
111
|
- lib/archival/version.rb
|
112
|
+
- lib/tags/asset.rb
|
94
113
|
- lib/tags/layout.rb
|
95
114
|
- package.json
|
96
115
|
homepage: https://archival.dev
|
97
116
|
licenses:
|
98
117
|
- Unlicense
|
99
|
-
metadata:
|
118
|
+
metadata:
|
119
|
+
rubygems_mfa_required: 'true'
|
100
120
|
post_install_message:
|
101
121
|
rdoc_options: []
|
102
122
|
require_paths:
|