dimples 6.5.3 → 7.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/bin/dimples +6 -74
- data/lib/dimples/document.rb +70 -0
- data/lib/dimples/page.rb +2 -65
- data/lib/dimples/pager.rb +6 -32
- data/lib/dimples/post.rb +10 -24
- data/lib/dimples/site.rb +99 -179
- data/lib/dimples/template.rb +2 -25
- data/lib/dimples/version.rb +1 -1
- data/lib/dimples.rb +0 -15
- metadata +16 -110
- data/lib/dimples/archive.rb +0 -64
- data/lib/dimples/category.rb +0 -18
- data/lib/dimples/configuration.rb +0 -76
- data/lib/dimples/errors.rb +0 -12
- data/lib/dimples/feed.rb +0 -14
- data/lib/dimples/frontmatter.rb +0 -19
- data/lib/dimples/renderer.rb +0 -58
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 882aeff0d91ba61d58f331bedabeba0c865dbb7ef355c1fdafde7e1605113d2e
|
4
|
+
data.tar.gz: 8ddfc8ea5bcbce38a35c8d0153f96adc4866f5529a074884e966b92a65dce642
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cc9caa2de2a10ac6a30f84876ad3a3e9bd070b2e3e9783f38763035d286ec46d55343fa6fbf5cb44c6b72fe3c67d773af7918cbcb714cdb10f2c4b4a6b52b1e4
|
7
|
+
data.tar.gz: 04510c31f0ee4de0d1e035ddf56003f12e4553bdaaf1b4a8f82d24c0344bae443443b8d4f73c58e6ae7c3a5447e73f734f315964c30dcb400f85b28fa9066042
|
data/bin/dimples
CHANGED
@@ -4,79 +4,11 @@
|
|
4
4
|
$LOAD_PATH.unshift(File.join(__dir__, '..', 'lib'))
|
5
5
|
|
6
6
|
require 'dimples'
|
7
|
-
require 'dimples/version'
|
8
|
-
require 'optimist'
|
9
|
-
require 'json'
|
10
7
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
8
|
+
path = if ARGV[0]
|
9
|
+
File.expand_path(ARGV[0])
|
10
|
+
else
|
11
|
+
File.join(Dir.pwd(), 'site')
|
12
|
+
end
|
15
13
|
|
16
|
-
|
17
|
-
|
18
|
-
options = Optimist.options do
|
19
|
-
version "dimples v#{Dimples::VERSION}"
|
20
|
-
banner <<-BANNER
|
21
|
-
A simple static site generator.
|
22
|
-
|
23
|
-
Usage:
|
24
|
-
dimples <#{valid_commands.join('|')}> [options]
|
25
|
-
|
26
|
-
Options:
|
27
|
-
BANNER
|
28
|
-
|
29
|
-
opt :config, 'Config file path', type: :string
|
30
|
-
opt :source, 'Source directory', type: :string
|
31
|
-
opt :destination, 'Destination directory', type: :string
|
32
|
-
end
|
33
|
-
|
34
|
-
Optimist.educate if ARGV.empty?
|
35
|
-
command = ARGV[0]
|
36
|
-
|
37
|
-
unless valid_commands.include?(command)
|
38
|
-
Optimist.die "Command must be '#{valid_commands.join('\', \'')}'"
|
39
|
-
end
|
40
|
-
|
41
|
-
source_path = if options[:source]
|
42
|
-
File.expand_path(options[:source])
|
43
|
-
else
|
44
|
-
Dir.pwd
|
45
|
-
end
|
46
|
-
|
47
|
-
config_path = options[:config] || File.join(source_path, 'config.json')
|
48
|
-
|
49
|
-
unless File.exist?(config_path)
|
50
|
-
Optimist.die "Unable to find config file (#{config_path})"
|
51
|
-
end
|
52
|
-
|
53
|
-
begin
|
54
|
-
file_contents = File.read(config_path)
|
55
|
-
Optimist.die "Config file is empty (#{config_path})" if file_contents.empty?
|
56
|
-
|
57
|
-
config = JSON.parse(file_contents, symbolize_names: true)
|
58
|
-
rescue JSON::ParserError
|
59
|
-
Optimist.die "Invalid or malformed config file (#{config_path})"
|
60
|
-
end
|
61
|
-
|
62
|
-
config[:source] = source_path
|
63
|
-
|
64
|
-
if options[:destination]
|
65
|
-
config[:destination] = File.expand_path(options[:destination])
|
66
|
-
end
|
67
|
-
|
68
|
-
site = Dimples::Site.new(config)
|
69
|
-
|
70
|
-
case command.to_sym
|
71
|
-
when :build
|
72
|
-
puts 'Building site...'
|
73
|
-
|
74
|
-
site.generate
|
75
|
-
|
76
|
-
if site.errors.empty?
|
77
|
-
puts "Done! Your site has been built in #{site.paths[:destination]}."
|
78
|
-
else
|
79
|
-
puts 'Generation failed:'
|
80
|
-
site.errors.each { |error| puts error }
|
81
|
-
end
|
82
|
-
end
|
14
|
+
Dimples::Site.generate(path)
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Dimples
|
4
|
+
class Document
|
5
|
+
FRONT_MATTER_PATTERN = /^(-{3}\n.*?\n?)^(-{3}*$\n?)/m.freeze
|
6
|
+
|
7
|
+
attr_accessor :metadata, :contents, :path, :rendered_contents
|
8
|
+
|
9
|
+
def initialize(path = nil)
|
10
|
+
@path = path
|
11
|
+
@metadata = {}
|
12
|
+
|
13
|
+
if @path
|
14
|
+
@contents = File.read(path)
|
15
|
+
|
16
|
+
if matches = contents.match(FRONT_MATTER_PATTERN)
|
17
|
+
@metadata = YAML.load(matches[1], symbolize_names: true)
|
18
|
+
@contents = matches.post_match.strip
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def filename
|
24
|
+
"#{basename}.#{extension}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def basename
|
28
|
+
@metadata.fetch(:filename, 'index')
|
29
|
+
end
|
30
|
+
|
31
|
+
def extension
|
32
|
+
@metadata.fetch(:extension, 'html')
|
33
|
+
end
|
34
|
+
|
35
|
+
def layout
|
36
|
+
@metadata.fetch(:layout, nil)
|
37
|
+
end
|
38
|
+
|
39
|
+
def render(context = {}, content = '')
|
40
|
+
context_obj = Object.new
|
41
|
+
context.each do |key, value|
|
42
|
+
context_obj.instance_variable_set("@#{key}", value)
|
43
|
+
end
|
44
|
+
|
45
|
+
@rendered_contents = renderer.render(context_obj) { content }
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def renderer
|
51
|
+
@renderer ||= begin
|
52
|
+
callback = proc { contents }
|
53
|
+
|
54
|
+
if @path
|
55
|
+
Tilt.new(@path, {}, &callback)
|
56
|
+
else
|
57
|
+
Tilt::StringTemplate.new(&callback)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def method_missing(method_name, *args, &block)
|
63
|
+
if @metadata.key?(method_name)
|
64
|
+
@metadata[method_name]
|
65
|
+
else
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
data/lib/dimples/page.rb
CHANGED
@@ -1,69 +1,6 @@
|
|
1
|
-
|
1
|
+
require_relative 'document'
|
2
2
|
|
3
3
|
module Dimples
|
4
|
-
|
5
|
-
class Page
|
6
|
-
attr_accessor :contents
|
7
|
-
attr_accessor :metadata
|
8
|
-
attr_accessor :path
|
9
|
-
|
10
|
-
def initialize(site, path = nil)
|
11
|
-
@site = site
|
12
|
-
@path = path
|
13
|
-
|
14
|
-
if @path
|
15
|
-
data = File.read(@path)
|
16
|
-
@contents, @metadata = FrontMatter.parse(data)
|
17
|
-
else
|
18
|
-
@contents = ''
|
19
|
-
@metadata = {}
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def filename
|
24
|
-
@metadata[:filename] || 'index'
|
25
|
-
end
|
26
|
-
|
27
|
-
def extension
|
28
|
-
@metadata[:extension] || 'html'
|
29
|
-
end
|
30
|
-
|
31
|
-
def render(context = {})
|
32
|
-
metadata = @metadata.dup
|
33
|
-
metadata.merge!(context[:page]) if context[:page]
|
34
|
-
|
35
|
-
context[:page] = Hashie::Mash.new(metadata)
|
36
|
-
|
37
|
-
renderer.render(context)
|
38
|
-
end
|
39
|
-
|
40
|
-
def write(output_directory, context = {})
|
41
|
-
FileUtils.mkdir_p(output_directory) unless Dir.exist?(output_directory)
|
42
|
-
output_path = File.join(output_directory, "#{filename}.#{extension}")
|
43
|
-
|
44
|
-
File.write(output_path, render(context))
|
45
|
-
rescue SystemCallError => e
|
46
|
-
raise PublishingError, "Failed to publish file at #{output_path} (#{e})"
|
47
|
-
end
|
48
|
-
|
49
|
-
private
|
50
|
-
|
51
|
-
def renderer
|
52
|
-
@renderer ||= Renderer.new(@site, self)
|
53
|
-
end
|
54
|
-
|
55
|
-
def method_missing(method_name, *args, &block)
|
56
|
-
if @metadata.key?(method_name)
|
57
|
-
@metadata[method_name]
|
58
|
-
elsif (matches = method_name.match(/([a-z_]+)=/))
|
59
|
-
@metadata[matches[1].to_sym] = args[0]
|
60
|
-
else
|
61
|
-
super
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
def respond_to_missing?(method_name, include_private = false)
|
66
|
-
@metadata.key?(method_name) || method_name.match?(/([a-z_]+)=/) || super
|
67
|
-
end
|
4
|
+
class Page < Document
|
68
5
|
end
|
69
6
|
end
|
data/lib/dimples/pager.rb
CHANGED
@@ -1,9 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Dimples
|
4
|
-
# A paginated collection of posts that can be walked forward or backwards.
|
5
4
|
class Pager
|
6
|
-
|
5
|
+
PER_PAGE = 5
|
7
6
|
|
8
7
|
include Enumerable
|
9
8
|
|
@@ -11,37 +10,12 @@ module Dimples
|
|
11
10
|
attr_reader :previous_page
|
12
11
|
attr_reader :next_page
|
13
12
|
attr_reader :page_count
|
14
|
-
attr_reader :item_count
|
15
|
-
|
16
|
-
def self.paginate(site, posts, path, layout, context = {})
|
17
|
-
pager = Pager.new(
|
18
|
-
path.sub(site.paths[:destination], '') + '/',
|
19
|
-
posts,
|
20
|
-
site.config.pagination
|
21
|
-
)
|
22
|
-
|
23
|
-
pager.each do |index|
|
24
|
-
page = Page.new(site)
|
25
|
-
page.layout = layout
|
26
|
-
|
27
|
-
page_path = if index == 1
|
28
|
-
path
|
29
|
-
else
|
30
|
-
File.join(path, "page_#{index}")
|
31
|
-
end
|
32
|
-
|
33
|
-
page.write(
|
34
|
-
page_path,
|
35
|
-
context.merge(pagination: pager.to_context)
|
36
|
-
)
|
37
|
-
end
|
38
|
-
end
|
39
13
|
|
40
|
-
def initialize(url, posts
|
14
|
+
def initialize(url, posts)
|
41
15
|
@url = url
|
42
16
|
@posts = posts
|
43
|
-
@per_page =
|
44
|
-
@page_prefix =
|
17
|
+
@per_page = PER_PAGE
|
18
|
+
@page_prefix = 'page_'
|
45
19
|
@page_count = (posts.length.to_f / @per_page.to_i).ceil
|
46
20
|
|
47
21
|
step_to(1)
|
@@ -94,7 +68,7 @@ module Dimples
|
|
94
68
|
end
|
95
69
|
|
96
70
|
def to_context
|
97
|
-
|
71
|
+
{
|
98
72
|
posts: posts_at(current_page),
|
99
73
|
current_page: @current_page,
|
100
74
|
page_count: @page_count,
|
@@ -108,7 +82,7 @@ module Dimples
|
|
108
82
|
previous_page: previous_page_url,
|
109
83
|
next_page: next_page_url
|
110
84
|
}
|
111
|
-
|
85
|
+
}
|
112
86
|
end
|
113
87
|
end
|
114
88
|
end
|
data/lib/dimples/post.rb
CHANGED
@@ -1,33 +1,19 @@
|
|
1
|
-
|
1
|
+
require_relative 'document'
|
2
2
|
|
3
|
-
|
4
|
-
# A single dated post on a site.
|
5
|
-
class Post < Page
|
6
|
-
POST_FILENAME = /(\d{4})-(\d{2})-(\d{2})-(.+)/.freeze
|
7
|
-
|
8
|
-
def initialize(site, path)
|
9
|
-
super
|
10
|
-
|
11
|
-
parts = File.basename(path, File.extname(path)).match(POST_FILENAME)
|
12
|
-
|
13
|
-
@metadata[:layout] ||= @site.config.layouts.post
|
3
|
+
require 'date'
|
14
4
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
@metadata
|
19
|
-
end
|
20
|
-
|
21
|
-
def year
|
22
|
-
@year ||= @metadata[:date].strftime('%Y')
|
5
|
+
module Dimples
|
6
|
+
class Post < Document
|
7
|
+
def date
|
8
|
+
@metadata.fetch(:date, DateTime.now)
|
23
9
|
end
|
24
10
|
|
25
|
-
def
|
26
|
-
@
|
11
|
+
def layout
|
12
|
+
@metadata.fetch(:layout, 'post')
|
27
13
|
end
|
28
14
|
|
29
|
-
def
|
30
|
-
@
|
15
|
+
def slug
|
16
|
+
File.basename(@path, '.markdown')
|
31
17
|
end
|
32
18
|
end
|
33
19
|
end
|
data/lib/dimples/site.rb
CHANGED
@@ -1,164 +1,125 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'pager'
|
4
|
+
|
5
|
+
require 'fileutils'
|
6
|
+
require 'tilt'
|
7
|
+
|
3
8
|
module Dimples
|
4
|
-
# A collection of pages, posts and templates that can generate a website.
|
5
9
|
class Site
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
paths[:source] = File.expand_path(@config.source)
|
21
|
-
paths[:destination] = File.expand_path(@config.destination)
|
22
|
-
|
23
|
-
%w[pages posts static templates].each do |type|
|
24
|
-
paths[type.to_sym] = File.join(paths[:source], type)
|
25
|
-
end
|
10
|
+
def self.generate(output_path)
|
11
|
+
new(output_path).generate
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_accessor :posts, :categories
|
15
|
+
|
16
|
+
def initialize(output_path)
|
17
|
+
@paths = {
|
18
|
+
source: File.expand_path(Dir.pwd),
|
19
|
+
destination: File.expand_path(output_path)
|
20
|
+
}
|
21
|
+
|
22
|
+
%w[pages posts static templates].each do |type|
|
23
|
+
@paths[type.to_sym] = File.join(@paths[:source], type)
|
26
24
|
end
|
27
25
|
|
28
|
-
|
26
|
+
scan_posts
|
27
|
+
scan_pages
|
28
|
+
scan_templates
|
29
29
|
end
|
30
30
|
|
31
31
|
def generate
|
32
|
-
|
32
|
+
if Dir.exist?(@paths[:destination])
|
33
|
+
puts "Error: The output directory (#{@paths[:destination]}) already exists."
|
34
|
+
return
|
35
|
+
end
|
33
36
|
|
34
|
-
|
35
|
-
read_posts
|
36
|
-
read_pages
|
37
|
+
Dir.mkdir(@paths[:destination])
|
37
38
|
|
38
|
-
|
39
|
-
|
39
|
+
generate_posts
|
40
|
+
generate_pages
|
41
|
+
generate_categories
|
40
42
|
|
41
|
-
|
42
|
-
publish_pages
|
43
|
-
publish_archives if @config.generation.year_archives
|
44
|
-
publish_categories if @config.generation.categories
|
45
|
-
rescue PublishingError, RenderingError, GenerationError => e
|
46
|
-
@errors << e
|
43
|
+
copy_assets
|
47
44
|
end
|
48
45
|
|
49
|
-
|
50
|
-
@config.data || {}
|
51
|
-
end
|
46
|
+
private
|
52
47
|
|
53
|
-
def
|
54
|
-
|
48
|
+
def read_files(path)
|
49
|
+
Dir[File.join(path, '**', '*.*')].sort
|
55
50
|
end
|
56
51
|
|
57
|
-
|
52
|
+
def scan_posts
|
53
|
+
@posts = read_files(@paths[:posts]).map do |path|
|
54
|
+
Dimples::Post.new(path)
|
55
|
+
end
|
58
56
|
|
59
|
-
|
60
|
-
@archive = Dimples::Archive.new
|
57
|
+
@posts.sort_by! { |post| post.date }.reverse!
|
61
58
|
|
62
59
|
@categories = {}
|
63
|
-
@templates = {}
|
64
|
-
|
65
|
-
@pages = []
|
66
|
-
@posts = []
|
67
|
-
@errors = []
|
68
60
|
|
69
|
-
@
|
61
|
+
@posts.each do |post|
|
62
|
+
post.categories.each do |category|
|
63
|
+
@categories[category] ||= []
|
64
|
+
@categories[category] << post
|
65
|
+
end
|
66
|
+
end
|
70
67
|
end
|
71
68
|
|
72
|
-
def
|
73
|
-
|
69
|
+
def scan_pages
|
70
|
+
@pages = read_files(@paths[:pages]).map do |path|
|
71
|
+
Dimples::Page.new(path)
|
72
|
+
end
|
74
73
|
end
|
75
74
|
|
76
|
-
def
|
77
|
-
@templates = {}
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
dir_name = File.dirname(path)
|
82
|
-
|
83
|
-
unless dir_name == @paths[:templates]
|
84
|
-
basename = dir_name.split(File::SEPARATOR)[-1] + '.' + basename
|
75
|
+
def scan_templates
|
76
|
+
@templates = {}.tap do |templates|
|
77
|
+
read_files(@paths[:templates]).each do |path|
|
78
|
+
key = File.basename(path, '.erb')
|
79
|
+
templates[key] = Dimples::Template.new(path)
|
85
80
|
end
|
86
|
-
|
87
|
-
@templates[basename] = Template.new(self, path)
|
88
81
|
end
|
89
82
|
end
|
90
83
|
|
91
|
-
def
|
92
|
-
|
93
|
-
Post.new(self, path).tap do |post|
|
94
|
-
@archive.add_post(post)
|
95
|
-
categorise_post(post)
|
96
|
-
end
|
97
|
-
end.reverse
|
84
|
+
def write_file(path, content)
|
85
|
+
directory_path = File.dirname(path)
|
98
86
|
|
99
|
-
|
87
|
+
Dir.mkdir(directory_path) unless Dir.exist?(directory_path)
|
88
|
+
File.write(path, content)
|
100
89
|
end
|
101
90
|
|
102
|
-
def
|
103
|
-
|
104
|
-
end
|
91
|
+
def generate_paginated_posts(posts, path, context = {})
|
92
|
+
pager = Dimples::Pager.new(path.sub(@paths[:destination], '') + '/', posts)
|
105
93
|
|
106
|
-
|
107
|
-
|
108
|
-
|
94
|
+
pager.each do |index|
|
95
|
+
page = Dimples::Page.new()
|
96
|
+
page.metadata[:layout] = 'posts'
|
109
97
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
98
|
+
page_path = if index == 1
|
99
|
+
path
|
100
|
+
else
|
101
|
+
File.join(path, "page_#{index}")
|
102
|
+
end
|
114
103
|
|
115
|
-
|
116
|
-
|
117
|
-
FileUtils.rm_r(@paths[:destination], secure: true)
|
118
|
-
else
|
119
|
-
FileUtils.mkdir_p(@paths[:destination])
|
104
|
+
context.merge!(pagination: pager.to_context)
|
105
|
+
write_file(File.join(page_path, page.filename), render(page, context))
|
120
106
|
end
|
121
|
-
rescue StandardError => e
|
122
|
-
message = "Couldn't prepare the output directory (#{e.message})"
|
123
|
-
raise GenerationError, message
|
124
107
|
end
|
125
108
|
|
126
|
-
def
|
127
|
-
|
128
|
-
|
129
|
-
FileUtils.cp_r(File.join(@paths[:static], '.'), @paths[:destination])
|
130
|
-
rescue StandardError => e
|
131
|
-
raise GenerationError, "Failed to copy site assets (#{e.message})"
|
132
|
-
end
|
109
|
+
def generate_posts
|
110
|
+
directory_path = File.join(@paths[:destination], 'posts')
|
111
|
+
Dir.mkdir(directory_path)
|
133
112
|
|
134
|
-
def publish_posts
|
135
113
|
@posts.each do |post|
|
136
|
-
path = File.join(
|
137
|
-
|
138
|
-
post.date.strftime(post.draft ? @config.paths.drafts : @config.paths.posts),
|
139
|
-
post.slug
|
140
|
-
)
|
141
|
-
|
142
|
-
post.write(path)
|
114
|
+
path = File.join(directory_path, post.slug, post.filename)
|
115
|
+
write_file(path, render(post, post: post))
|
143
116
|
end
|
144
117
|
|
145
|
-
|
146
|
-
|
147
|
-
if @config.generation.main_feed
|
148
|
-
publish_feeds(published_posts, @paths[:destination])
|
149
|
-
end
|
150
|
-
|
151
|
-
return unless @config.generation.paginated_posts
|
152
|
-
|
153
|
-
Dimples::Pager.paginate(
|
154
|
-
self,
|
155
|
-
published_posts,
|
156
|
-
File.join(@paths[:destination], @config.paths.paginated_posts),
|
157
|
-
@config.layouts.paginated_post
|
158
|
-
)
|
118
|
+
generate_paginated_posts(@posts, directory_path)
|
119
|
+
generate_feed(@posts.slice(0, 10), @paths[:destination])
|
159
120
|
end
|
160
121
|
|
161
|
-
def
|
122
|
+
def generate_pages
|
162
123
|
@pages.each do |page|
|
163
124
|
path = if page.path
|
164
125
|
File.dirname(page.path).sub(
|
@@ -169,82 +130,41 @@ module Dimples
|
|
169
130
|
@paths[:destination]
|
170
131
|
end
|
171
132
|
|
172
|
-
|
133
|
+
write_file(File.join(path, page.filename), render(page, page: page))
|
173
134
|
end
|
174
135
|
end
|
175
136
|
|
176
|
-
def
|
177
|
-
@
|
178
|
-
|
179
|
-
next unless @config.generation.month_archives
|
180
|
-
|
181
|
-
@archive.months(year).each do |month|
|
182
|
-
publish_archive(year, month)
|
183
|
-
next unless @config.generation.day_archives
|
137
|
+
def generate_categories
|
138
|
+
@categories.each do |category, posts|
|
139
|
+
category_path = File.join(@paths[:destination], 'categories', category)
|
184
140
|
|
185
|
-
|
186
|
-
|
187
|
-
end
|
188
|
-
end
|
141
|
+
generate_paginated_posts(posts, category_path, category: category)
|
142
|
+
generate_feed(posts.slice(0, 10), category_path)
|
189
143
|
end
|
190
144
|
end
|
191
145
|
|
192
|
-
def
|
193
|
-
|
194
|
-
|
195
|
-
elsif month
|
196
|
-
'month'
|
197
|
-
else
|
198
|
-
'year'
|
199
|
-
end
|
200
|
-
|
201
|
-
posts = @archive.posts_for_date(year, month, day)
|
202
|
-
|
203
|
-
date_parts = [year, month, day].compact
|
204
|
-
path = File.join(@paths[:destination], @config.paths.archives, date_parts)
|
205
|
-
layout = @config.layouts.date_archive
|
206
|
-
|
207
|
-
data = {
|
208
|
-
page: {
|
209
|
-
title: posts[0].date.strftime(@config.date_formats[date_type]),
|
210
|
-
archive_date: posts[0].date,
|
211
|
-
archive_type: date_type
|
212
|
-
}
|
213
|
-
}
|
146
|
+
def generate_feed(posts, path)
|
147
|
+
page = Dimples::Page.new()
|
148
|
+
page.metadata[:layout] = 'feed'
|
214
149
|
|
215
|
-
|
150
|
+
write_file(File.join(path, 'feed.atom'), render(page, posts: posts))
|
216
151
|
end
|
217
152
|
|
218
|
-
def
|
219
|
-
|
220
|
-
|
221
|
-
@paths[:destination],
|
222
|
-
@config.paths.categories,
|
223
|
-
category.slug
|
224
|
-
)
|
225
|
-
|
226
|
-
category_posts = category.posts.reverse
|
227
|
-
context = { page: { title: category.name, category: category } }
|
228
|
-
|
229
|
-
Dimples::Pager.paginate(
|
230
|
-
self,
|
231
|
-
category_posts,
|
232
|
-
path,
|
233
|
-
@config.layouts.category,
|
234
|
-
context
|
235
|
-
)
|
236
|
-
|
237
|
-
publish_feeds(category_posts, path, context)
|
238
|
-
end
|
153
|
+
def copy_assets
|
154
|
+
return unless Dir.exist?(@paths[:static])
|
155
|
+
FileUtils.cp_r(File.join(@paths[:static], '.'), @paths[:destination])
|
239
156
|
end
|
240
157
|
|
241
|
-
def
|
242
|
-
|
243
|
-
|
158
|
+
def render(object, context = {}, content = nil)
|
159
|
+
context[:site] ||= self
|
160
|
+
|
161
|
+
output = object.render(context, content)
|
244
162
|
|
245
|
-
|
246
|
-
|
163
|
+
if object.layout && @templates[object.layout]
|
164
|
+
output = render(@templates[object.layout], context, output)
|
247
165
|
end
|
166
|
+
|
167
|
+
output
|
248
168
|
end
|
249
169
|
end
|
250
170
|
end
|
data/lib/dimples/template.rb
CHANGED
@@ -1,29 +1,6 @@
|
|
1
|
-
|
1
|
+
require_relative 'document'
|
2
2
|
|
3
3
|
module Dimples
|
4
|
-
|
5
|
-
class Template
|
6
|
-
attr_accessor :path
|
7
|
-
attr_accessor :contents
|
8
|
-
attr_accessor :metadata
|
9
|
-
|
10
|
-
def initialize(site, path)
|
11
|
-
@site = site
|
12
|
-
@path = path
|
13
|
-
|
14
|
-
data = File.read(path)
|
15
|
-
@contents, @metadata = FrontMatter.parse(data)
|
16
|
-
end
|
17
|
-
|
18
|
-
def render(context = {}, body = nil)
|
19
|
-
context[:template] ||= Hashie::Mash.new(@metadata)
|
20
|
-
renderer.render(context, body)
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
def renderer
|
26
|
-
@renderer ||= Renderer.new(@site, self)
|
27
|
-
end
|
4
|
+
class Template < Document
|
28
5
|
end
|
29
6
|
end
|
data/lib/dimples/version.rb
CHANGED
data/lib/dimples.rb
CHANGED
@@ -2,22 +2,7 @@
|
|
2
2
|
|
3
3
|
$LOAD_PATH.unshift(__dir__)
|
4
4
|
|
5
|
-
require 'fileutils'
|
6
|
-
require 'hashie'
|
7
|
-
require 'tilt'
|
8
|
-
require 'yaml'
|
9
|
-
|
10
|
-
require 'dimples/archive'
|
11
|
-
require 'dimples/category'
|
12
|
-
require 'dimples/configuration'
|
13
|
-
require 'dimples/errors'
|
14
|
-
require 'dimples/frontmatter'
|
15
|
-
require 'dimples/pager'
|
16
|
-
require 'dimples/renderer'
|
17
|
-
|
18
5
|
require 'dimples/page'
|
19
|
-
require 'dimples/feed'
|
20
6
|
require 'dimples/post'
|
21
7
|
require 'dimples/template'
|
22
|
-
|
23
8
|
require 'dimples/site'
|
metadata
CHANGED
@@ -1,49 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dimples
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: '7.0'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Bogan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-08-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: erubi
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
20
|
-
- - ">="
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: 3.5.7
|
23
|
-
type: :runtime
|
24
|
-
prerelease: false
|
25
|
-
version_requirements: !ruby/object:Gem::Requirement
|
26
|
-
requirements:
|
27
|
-
- - "~>"
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: '3.5'
|
30
|
-
- - ">="
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: 3.5.7
|
33
|
-
- !ruby/object:Gem::Dependency
|
34
|
-
name: optimist
|
35
|
-
requirement: !ruby/object:Gem::Requirement
|
36
|
-
requirements:
|
37
|
-
- - "~>"
|
38
|
-
- !ruby/object:Gem::Version
|
39
|
-
version: '3.0'
|
19
|
+
version: '1.10'
|
40
20
|
type: :runtime
|
41
21
|
prerelease: false
|
42
22
|
version_requirements: !ruby/object:Gem::Requirement
|
43
23
|
requirements:
|
44
24
|
- - "~>"
|
45
25
|
- !ruby/object:Gem::Version
|
46
|
-
version: '
|
26
|
+
version: '1.10'
|
47
27
|
- !ruby/object:Gem::Dependency
|
48
28
|
name: tilt
|
49
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -59,115 +39,47 @@ dependencies:
|
|
59
39
|
- !ruby/object:Gem::Version
|
60
40
|
version: '2.0'
|
61
41
|
- !ruby/object:Gem::Dependency
|
62
|
-
name:
|
63
|
-
requirement: !ruby/object:Gem::Requirement
|
64
|
-
requirements:
|
65
|
-
- - ">="
|
66
|
-
- !ruby/object:Gem::Version
|
67
|
-
version: 1.0.0
|
68
|
-
- - "~>"
|
69
|
-
- !ruby/object:Gem::Version
|
70
|
-
version: '1.0'
|
71
|
-
type: :development
|
72
|
-
prerelease: false
|
73
|
-
version_requirements: !ruby/object:Gem::Requirement
|
74
|
-
requirements:
|
75
|
-
- - ">="
|
76
|
-
- !ruby/object:Gem::Version
|
77
|
-
version: 1.0.0
|
78
|
-
- - "~>"
|
79
|
-
- !ruby/object:Gem::Version
|
80
|
-
version: '1.0'
|
81
|
-
- !ruby/object:Gem::Dependency
|
82
|
-
name: erubis
|
42
|
+
name: redcarpet
|
83
43
|
requirement: !ruby/object:Gem::Requirement
|
84
44
|
requirements:
|
85
45
|
- - "~>"
|
86
46
|
- !ruby/object:Gem::Version
|
87
|
-
version: '
|
88
|
-
type: :
|
47
|
+
version: '3.5'
|
48
|
+
type: :runtime
|
89
49
|
prerelease: false
|
90
50
|
version_requirements: !ruby/object:Gem::Requirement
|
91
51
|
requirements:
|
92
52
|
- - "~>"
|
93
53
|
- !ruby/object:Gem::Version
|
94
|
-
version: '
|
54
|
+
version: '3.5'
|
95
55
|
- !ruby/object:Gem::Dependency
|
96
56
|
name: rake
|
97
57
|
requirement: !ruby/object:Gem::Requirement
|
98
58
|
requirements:
|
99
59
|
- - "~>"
|
100
60
|
- !ruby/object:Gem::Version
|
101
|
-
version:
|
61
|
+
version: 12.3.3
|
102
62
|
type: :development
|
103
63
|
prerelease: false
|
104
64
|
version_requirements: !ruby/object:Gem::Requirement
|
105
65
|
requirements:
|
106
66
|
- - "~>"
|
107
67
|
- !ruby/object:Gem::Version
|
108
|
-
version:
|
109
|
-
- !ruby/object:Gem::Dependency
|
110
|
-
name: redcarpet
|
111
|
-
requirement: !ruby/object:Gem::Requirement
|
112
|
-
requirements:
|
113
|
-
- - "~>"
|
114
|
-
- !ruby/object:Gem::Version
|
115
|
-
version: '3.3'
|
116
|
-
type: :development
|
117
|
-
prerelease: false
|
118
|
-
version_requirements: !ruby/object:Gem::Requirement
|
119
|
-
requirements:
|
120
|
-
- - "~>"
|
121
|
-
- !ruby/object:Gem::Version
|
122
|
-
version: '3.3'
|
68
|
+
version: 12.3.3
|
123
69
|
- !ruby/object:Gem::Dependency
|
124
70
|
name: rspec
|
125
|
-
requirement: !ruby/object:Gem::Requirement
|
126
|
-
requirements:
|
127
|
-
- - ">="
|
128
|
-
- !ruby/object:Gem::Version
|
129
|
-
version: 3.7.0
|
130
|
-
- - "~>"
|
131
|
-
- !ruby/object:Gem::Version
|
132
|
-
version: '3.7'
|
133
|
-
type: :development
|
134
|
-
prerelease: false
|
135
|
-
version_requirements: !ruby/object:Gem::Requirement
|
136
|
-
requirements:
|
137
|
-
- - ">="
|
138
|
-
- !ruby/object:Gem::Version
|
139
|
-
version: 3.7.0
|
140
|
-
- - "~>"
|
141
|
-
- !ruby/object:Gem::Version
|
142
|
-
version: '3.7'
|
143
|
-
- !ruby/object:Gem::Dependency
|
144
|
-
name: simplecov
|
145
|
-
requirement: !ruby/object:Gem::Requirement
|
146
|
-
requirements:
|
147
|
-
- - "~>"
|
148
|
-
- !ruby/object:Gem::Version
|
149
|
-
version: '0.14'
|
150
|
-
type: :development
|
151
|
-
prerelease: false
|
152
|
-
version_requirements: !ruby/object:Gem::Requirement
|
153
|
-
requirements:
|
154
|
-
- - "~>"
|
155
|
-
- !ruby/object:Gem::Version
|
156
|
-
version: '0.14'
|
157
|
-
- !ruby/object:Gem::Dependency
|
158
|
-
name: timecop
|
159
71
|
requirement: !ruby/object:Gem::Requirement
|
160
72
|
requirements:
|
161
73
|
- - "~>"
|
162
74
|
- !ruby/object:Gem::Version
|
163
|
-
version:
|
75
|
+
version: '3.10'
|
164
76
|
type: :development
|
165
77
|
prerelease: false
|
166
78
|
version_requirements: !ruby/object:Gem::Requirement
|
167
79
|
requirements:
|
168
80
|
- - "~>"
|
169
81
|
- !ruby/object:Gem::Version
|
170
|
-
version:
|
82
|
+
version: '3.10'
|
171
83
|
description: A simple tool for building static websites.
|
172
84
|
email:
|
173
85
|
- d+dimples@waferbaby.com
|
@@ -178,16 +90,10 @@ extra_rdoc_files: []
|
|
178
90
|
files:
|
179
91
|
- bin/dimples
|
180
92
|
- lib/dimples.rb
|
181
|
-
- lib/dimples/
|
182
|
-
- lib/dimples/category.rb
|
183
|
-
- lib/dimples/configuration.rb
|
184
|
-
- lib/dimples/errors.rb
|
185
|
-
- lib/dimples/feed.rb
|
186
|
-
- lib/dimples/frontmatter.rb
|
93
|
+
- lib/dimples/document.rb
|
187
94
|
- lib/dimples/page.rb
|
188
95
|
- lib/dimples/pager.rb
|
189
96
|
- lib/dimples/post.rb
|
190
|
-
- lib/dimples/renderer.rb
|
191
97
|
- lib/dimples/site.rb
|
192
98
|
- lib/dimples/template.rb
|
193
99
|
- lib/dimples/version.rb
|
@@ -203,14 +109,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
203
109
|
requirements:
|
204
110
|
- - "~>"
|
205
111
|
- !ruby/object:Gem::Version
|
206
|
-
version: '2.
|
112
|
+
version: '2.7'
|
207
113
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
208
114
|
requirements:
|
209
115
|
- - ">="
|
210
116
|
- !ruby/object:Gem::Version
|
211
117
|
version: '0'
|
212
118
|
requirements: []
|
213
|
-
rubygems_version: 3.
|
119
|
+
rubygems_version: 3.1.6
|
214
120
|
signing_key:
|
215
121
|
specification_version: 4
|
216
122
|
summary: A basic static site generator
|
data/lib/dimples/archive.rb
DELETED
@@ -1,64 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Dimples
|
4
|
-
# A collection of posts, organised by date.
|
5
|
-
class Archive
|
6
|
-
def initialize
|
7
|
-
@years = {}
|
8
|
-
end
|
9
|
-
|
10
|
-
def add_post(post)
|
11
|
-
year(post.year)[:posts] << post
|
12
|
-
month(post.year, post.month)[:posts] << post
|
13
|
-
day(post.year, post.month, post.day)[:posts] << post
|
14
|
-
end
|
15
|
-
|
16
|
-
def years
|
17
|
-
@years.keys
|
18
|
-
end
|
19
|
-
|
20
|
-
def months(year)
|
21
|
-
year(year)[:months].keys
|
22
|
-
end
|
23
|
-
|
24
|
-
def days(year, month)
|
25
|
-
month(year, month)[:days].keys
|
26
|
-
end
|
27
|
-
|
28
|
-
def posts_for_date(year, month = nil, day = nil)
|
29
|
-
if day
|
30
|
-
day_posts(year, month, day)
|
31
|
-
elsif month
|
32
|
-
month_posts(year, month)
|
33
|
-
else
|
34
|
-
year_posts(year)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def year_posts(year)
|
39
|
-
year(year)[:posts]
|
40
|
-
end
|
41
|
-
|
42
|
-
def month_posts(year, month)
|
43
|
-
month(year, month)[:posts]
|
44
|
-
end
|
45
|
-
|
46
|
-
def day_posts(year, month, day)
|
47
|
-
day(year, month, day)[:posts]
|
48
|
-
end
|
49
|
-
|
50
|
-
private
|
51
|
-
|
52
|
-
def year(year)
|
53
|
-
@years[year.to_s] ||= { months: {}, posts: [] }
|
54
|
-
end
|
55
|
-
|
56
|
-
def month(year, month)
|
57
|
-
year(year)[:months][month.to_s] ||= { days: {}, posts: [] }
|
58
|
-
end
|
59
|
-
|
60
|
-
def day(year, month, day)
|
61
|
-
month(year, month)[:days][day.to_s] ||= { posts: [] }
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
data/lib/dimples/category.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Dimples
|
4
|
-
# A single post category for a site.
|
5
|
-
class Category
|
6
|
-
attr_reader :name
|
7
|
-
attr_reader :slug
|
8
|
-
attr_accessor :posts
|
9
|
-
|
10
|
-
def initialize(site, slug)
|
11
|
-
@site = site
|
12
|
-
@slug = slug
|
13
|
-
@name = @site.config.category_names[slug.to_sym] || slug.capitalize
|
14
|
-
|
15
|
-
@posts = []
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
@@ -1,76 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Dimples
|
4
|
-
# Default configuration options for a site.
|
5
|
-
module Configuration
|
6
|
-
def self.prepare(config)
|
7
|
-
Hashie::Mash.new(defaults).deep_merge(config)
|
8
|
-
end
|
9
|
-
|
10
|
-
def self.defaults
|
11
|
-
{
|
12
|
-
source: Dir.pwd,
|
13
|
-
destination: File.join(Dir.pwd, 'public'),
|
14
|
-
paths: default_paths,
|
15
|
-
generation: default_generation,
|
16
|
-
layouts: default_layouts,
|
17
|
-
pagination: default_pagination,
|
18
|
-
date_formats: default_date_formats,
|
19
|
-
feed_formats: default_feed_formats,
|
20
|
-
category_names: {},
|
21
|
-
rendering: {}
|
22
|
-
}
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.default_paths
|
26
|
-
{
|
27
|
-
archives: 'archives',
|
28
|
-
paginated_posts: 'posts',
|
29
|
-
posts: 'archives/%Y/%m/%d',
|
30
|
-
drafts: 'archives/drafts/%Y/%m/%d',
|
31
|
-
categories: 'archives/categories'
|
32
|
-
}
|
33
|
-
end
|
34
|
-
|
35
|
-
def self.default_generation
|
36
|
-
{
|
37
|
-
paginated_posts: true,
|
38
|
-
year_archives: true,
|
39
|
-
month_archives: true,
|
40
|
-
day_archives: true,
|
41
|
-
categories: true,
|
42
|
-
main_feed: true,
|
43
|
-
category_feeds: true
|
44
|
-
}
|
45
|
-
end
|
46
|
-
|
47
|
-
def self.default_layouts
|
48
|
-
{
|
49
|
-
post: 'post',
|
50
|
-
category: 'category',
|
51
|
-
paginated_post: 'paginated_post',
|
52
|
-
archive: 'archive',
|
53
|
-
date_archive: 'archive'
|
54
|
-
}
|
55
|
-
end
|
56
|
-
|
57
|
-
def self.default_date_formats
|
58
|
-
{
|
59
|
-
year: '%Y',
|
60
|
-
month: '%Y-%m',
|
61
|
-
day: '%Y-%m-%d'
|
62
|
-
}
|
63
|
-
end
|
64
|
-
|
65
|
-
def self.default_feed_formats
|
66
|
-
['atom']
|
67
|
-
end
|
68
|
-
|
69
|
-
def self.default_pagination
|
70
|
-
{
|
71
|
-
page_prefix: 'page_',
|
72
|
-
per_page: 10
|
73
|
-
}
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
data/lib/dimples/errors.rb
DELETED
data/lib/dimples/feed.rb
DELETED
data/lib/dimples/frontmatter.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Dimples
|
4
|
-
# Adds the ability to parse front matter from a file.
|
5
|
-
class FrontMatter
|
6
|
-
FRONT_MATTER_PATTERN = /^(-{3}\n.*?\n?)^(-{3}*$\n?)/m.freeze
|
7
|
-
|
8
|
-
def self.parse(contents)
|
9
|
-
if (matches = contents.match(FRONT_MATTER_PATTERN))
|
10
|
-
metadata = Hashie.symbolize_keys(YAML.safe_load(matches[1]))
|
11
|
-
contents = matches.post_match.strip
|
12
|
-
else
|
13
|
-
metadata = {}
|
14
|
-
end
|
15
|
-
|
16
|
-
[contents, metadata]
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
data/lib/dimples/renderer.rb
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Dimples
|
4
|
-
# A wrapper around Tilt, tied to a single post, page or template.
|
5
|
-
class Renderer
|
6
|
-
def initialize(site, source)
|
7
|
-
@site = site
|
8
|
-
@source = source
|
9
|
-
end
|
10
|
-
|
11
|
-
def render(context = {}, body = nil)
|
12
|
-
context[:site] ||= @site
|
13
|
-
context[:pagination] ||= nil
|
14
|
-
|
15
|
-
begin
|
16
|
-
output = engine.render(scope, context) { body }.strip
|
17
|
-
rescue StandardError => e
|
18
|
-
raise RenderingError,
|
19
|
-
"Unable to render #{@source.path || 'dynamic file'} (#{e})"
|
20
|
-
end
|
21
|
-
|
22
|
-
@source.metadata[:rendered_contents] = output
|
23
|
-
|
24
|
-
if @source.metadata[:layout]
|
25
|
-
template = @site.templates[@source.metadata[:layout]]
|
26
|
-
end
|
27
|
-
|
28
|
-
return output if template.nil?
|
29
|
-
|
30
|
-
template.render(context, output)
|
31
|
-
end
|
32
|
-
|
33
|
-
def engine
|
34
|
-
@engine ||= begin
|
35
|
-
callback = proc { @source.contents }
|
36
|
-
|
37
|
-
if @source.path
|
38
|
-
extension = File.extname(@source.path)
|
39
|
-
options = @site.config.rendering[extension.to_sym] || {}
|
40
|
-
|
41
|
-
Tilt.new(@source.path, options, &callback)
|
42
|
-
else
|
43
|
-
Tilt::StringTemplate.new(&callback)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def scope
|
49
|
-
@scope ||= Object.new.tap do |scope|
|
50
|
-
scope.instance_variable_set(:@site, @site)
|
51
|
-
|
52
|
-
scope.class.send(:define_method, :render) do |layout, locals = {}|
|
53
|
-
@site.templates[layout]&.render(locals)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|