dimples 4.3.2 → 5.0.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 +5 -5
- data/bin/dimples +11 -31
- data/lib/dimples.rb +4 -15
- data/lib/dimples/category.rb +3 -3
- data/lib/dimples/configuration.rb +32 -48
- data/lib/dimples/errors.rb +5 -7
- data/lib/dimples/frontable.rb +8 -13
- data/lib/dimples/page.rb +40 -34
- data/lib/dimples/pager.rb +80 -0
- data/lib/dimples/plugin.rb +40 -0
- data/lib/dimples/post.rb +14 -30
- data/lib/dimples/renderer.rb +48 -0
- data/lib/dimples/site.rb +180 -201
- data/lib/dimples/template.rb +10 -9
- data/lib/dimples/version.rb +1 -1
- metadata +41 -29
- data/lib/dimples/logger.rb +0 -33
- data/lib/dimples/pagination.rb +0 -112
- data/lib/dimples/renderable.rb +0 -50
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d7a2db6d510cc724696cd9255569144515c7ad9afd10b4a6da596f50f492d4f9
|
4
|
+
data.tar.gz: f55f43d79d5137c22ccea11e27c50be6de043ee794f3d3ae3ea212508da6bebb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c86532b5690b9bc411d18357101799fe3e6e9c0a2c33ef9fabc2f3975b3fa9551cb45ae97768dcd96a6b0ec7388ceaba4bcdf0dc5a40b3a800ce10b3878c3085
|
7
|
+
data.tar.gz: 815be09d293fba723038a6fb0bbc6123434e03b34bdd7aa52438f276b234ea9e52cf661c2efa0c1120d72533c2149a81b2e5f8a87381ba1f666108b9166ed566
|
data/bin/dimples
CHANGED
@@ -18,7 +18,7 @@ valid_commands = %w[build]
|
|
18
18
|
options = Trollop.options do
|
19
19
|
version "dimples v#{Dimples::VERSION}"
|
20
20
|
banner <<-BANNER
|
21
|
-
A
|
21
|
+
A simple static site generator.
|
22
22
|
|
23
23
|
Usage:
|
24
24
|
dimples <#{valid_commands.join('|')}> [options]
|
@@ -26,7 +26,6 @@ dimples <#{valid_commands.join('|')}> [options]
|
|
26
26
|
Options:
|
27
27
|
BANNER
|
28
28
|
opt :config, 'Config file path', type: :string
|
29
|
-
opt :lib, 'Library file path', default: 'lib'
|
30
29
|
opt :verbose, 'Verbose mode', default: false
|
31
30
|
end
|
32
31
|
|
@@ -37,7 +36,7 @@ unless valid_commands.include?(command)
|
|
37
36
|
Trollop.die "Command must be '#{valid_commands.join('\', \'')}'"
|
38
37
|
end
|
39
38
|
|
40
|
-
|
39
|
+
plugins_path = File.join(Dir.pwd, 'plugins')
|
41
40
|
config_path = options[:config] || File.join(Dir.pwd, 'config.json')
|
42
41
|
|
43
42
|
if File.exist?(config_path)
|
@@ -53,43 +52,24 @@ else
|
|
53
52
|
Trollop.die "Unable to find config file (#{config_path})"
|
54
53
|
end
|
55
54
|
|
56
|
-
|
57
|
-
|
58
|
-
if Dir.exist?(lib_path)
|
59
|
-
Dir.glob(File.join(lib_path, '**', '*.rb')) do |path|
|
55
|
+
if Dir.exist?(plugins_path)
|
56
|
+
Dir.glob(File.join(plugins_path, '**', '*.rb')) do |path|
|
60
57
|
require path
|
61
58
|
end
|
62
59
|
end
|
63
60
|
|
64
|
-
|
65
|
-
|
66
|
-
site_klass = if site_klass_name
|
67
|
-
Object.const_get(site_klass_name)
|
68
|
-
else
|
69
|
-
Dimples::Site
|
70
|
-
end
|
71
|
-
|
72
|
-
site = site_klass.new(config)
|
61
|
+
site = Dimples::Site.new(config)
|
73
62
|
|
74
63
|
case command.to_sym
|
75
64
|
when :build
|
76
|
-
|
77
|
-
|
78
|
-
result = Benchmark.measure do
|
79
|
-
site.generate
|
80
|
-
end
|
81
|
-
|
82
|
-
if site.generated?
|
83
|
-
generation_time = result.real.round(2)
|
65
|
+
puts 'Building site...'
|
84
66
|
|
85
|
-
|
86
|
-
message += 's' if generation_time != 1
|
87
|
-
message += '.'
|
67
|
+
site.generate
|
88
68
|
|
89
|
-
|
69
|
+
if site.errors.empty?
|
70
|
+
puts 'Done! Your site has been built.'
|
90
71
|
else
|
91
|
-
|
92
|
-
|
93
|
-
end
|
72
|
+
puts 'Generation failed:'
|
73
|
+
site.errors.each { |error| puts error }
|
94
74
|
end
|
95
75
|
end
|
data/lib/dimples.rb
CHANGED
@@ -2,30 +2,19 @@
|
|
2
2
|
|
3
3
|
$LOAD_PATH.unshift(__dir__)
|
4
4
|
|
5
|
-
require '
|
6
|
-
require 'fileutils'
|
7
|
-
require 'logger'
|
5
|
+
require 'hashie'
|
8
6
|
require 'tilt'
|
9
7
|
require 'yaml'
|
10
8
|
|
11
9
|
require 'dimples/frontable'
|
12
|
-
require 'dimples/renderable'
|
13
10
|
|
14
11
|
require 'dimples/category'
|
15
12
|
require 'dimples/configuration'
|
16
13
|
require 'dimples/errors'
|
17
|
-
require 'dimples/logger'
|
18
14
|
require 'dimples/page'
|
19
|
-
require 'dimples/
|
15
|
+
require 'dimples/pager'
|
16
|
+
require 'dimples/plugin'
|
20
17
|
require 'dimples/post'
|
18
|
+
require 'dimples/renderer'
|
21
19
|
require 'dimples/site'
|
22
20
|
require 'dimples/template'
|
23
|
-
|
24
|
-
# A static site generator.
|
25
|
-
module Dimples
|
26
|
-
class << self
|
27
|
-
def logger
|
28
|
-
@logger ||= Dimples::Logger.new(STDOUT)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
data/lib/dimples/category.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Dimples
|
4
|
-
# A class that models a single interview category.
|
5
4
|
class Category
|
6
5
|
attr_accessor :name
|
7
6
|
attr_accessor :slug
|
@@ -10,12 +9,13 @@ module Dimples
|
|
10
9
|
def initialize(site, slug)
|
11
10
|
@site = site
|
12
11
|
@slug = slug
|
13
|
-
@name = @site.config
|
12
|
+
@name = @site.config.category_names[slug.to_sym] || slug.capitalize
|
13
|
+
|
14
14
|
@posts = []
|
15
15
|
end
|
16
16
|
|
17
17
|
def inspect
|
18
|
-
"#<#{self.class} @slug=#{
|
18
|
+
"#<#{self.class} @slug=#{slug} @name=#{name}>"
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
@@ -1,74 +1,47 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Dimples
|
4
|
-
|
5
|
-
|
6
|
-
def initialize(config = {})
|
7
|
-
@settings = Dimples::Configuration.default_settings
|
8
|
-
|
9
|
-
config.each_key do |key|
|
10
|
-
case @settings[key]
|
11
|
-
when Hash
|
12
|
-
@settings[key].merge!(config[key])
|
13
|
-
else
|
14
|
-
@settings[key] = config[key]
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def [](key)
|
20
|
-
@settings[key]
|
21
|
-
end
|
22
|
-
|
23
|
-
def self.default_settings
|
4
|
+
module Configuration
|
5
|
+
def self.defaults
|
24
6
|
{
|
25
|
-
source_path: Dir.pwd,
|
26
|
-
destination_path: File.join(Dir.pwd, 'site'),
|
27
|
-
verbose_logging: false,
|
28
|
-
class_overrides: { site: nil, post: nil },
|
29
|
-
rendering: {},
|
30
|
-
category_names: {},
|
31
7
|
paths: default_paths,
|
8
|
+
generation: default_generation,
|
32
9
|
layouts: default_layouts,
|
33
10
|
pagination: default_pagination,
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
def self.default_layouts
|
40
|
-
{
|
41
|
-
posts: 'posts',
|
42
|
-
post: 'post',
|
43
|
-
category: 'category',
|
44
|
-
year_archives: 'year_archives',
|
45
|
-
month_archives: 'month_archives',
|
46
|
-
day_archives: 'day_archives'
|
11
|
+
date_formats: default_date_formats,
|
12
|
+
feed_formats: default_feed_formats,
|
13
|
+
category_names: {},
|
14
|
+
rendering: {},
|
47
15
|
}
|
48
16
|
end
|
49
17
|
|
50
18
|
def self.default_paths
|
51
19
|
{
|
20
|
+
output: 'site',
|
52
21
|
archives: 'archives',
|
53
22
|
posts: 'archives/%Y/%m/%d',
|
54
23
|
categories: 'archives/categories'
|
55
24
|
}
|
56
25
|
end
|
57
26
|
|
58
|
-
def self.default_pagination
|
59
|
-
{
|
60
|
-
per_page: 10
|
61
|
-
}
|
62
|
-
end
|
63
|
-
|
64
27
|
def self.default_generation
|
65
28
|
{
|
66
|
-
|
29
|
+
archives: true,
|
67
30
|
year_archives: true,
|
68
31
|
month_archives: true,
|
69
32
|
day_archives: true,
|
70
|
-
|
71
|
-
|
33
|
+
categories: true,
|
34
|
+
main_feed: true,
|
35
|
+
category_feeds: true,
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.default_layouts
|
40
|
+
{
|
41
|
+
post: 'post',
|
42
|
+
category: 'category',
|
43
|
+
archive: 'archive',
|
44
|
+
date_archive: 'archive'
|
72
45
|
}
|
73
46
|
end
|
74
47
|
|
@@ -79,5 +52,16 @@ module Dimples
|
|
79
52
|
day: '%Y-%m-%d'
|
80
53
|
}
|
81
54
|
end
|
55
|
+
|
56
|
+
def self.default_feed_formats
|
57
|
+
['atom']
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.default_pagination
|
61
|
+
{
|
62
|
+
page_prefix: 'page',
|
63
|
+
per_page: 10
|
64
|
+
}
|
65
|
+
end
|
82
66
|
end
|
83
67
|
end
|
data/lib/dimples/errors.rb
CHANGED
@@ -1,14 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Dimples
|
4
|
-
|
5
|
-
|
6
|
-
end
|
4
|
+
class PublishingError < StandardError
|
5
|
+
end
|
7
6
|
|
8
|
-
|
9
|
-
|
7
|
+
class RenderingError < StandardError
|
8
|
+
end
|
10
9
|
|
11
|
-
|
12
|
-
end
|
10
|
+
class GenerationError < StandardError
|
13
11
|
end
|
14
12
|
end
|
data/lib/dimples/frontable.rb
CHANGED
@@ -1,23 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Dimples
|
4
|
-
# A mixin class that handles reading and parsing front matter from a file.
|
5
4
|
module Frontable
|
6
|
-
|
5
|
+
def read_with_front_matter(path)
|
6
|
+
contents = File.read(path)
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
YAML.safe_load(matches[1]).each_pair do |key, value|
|
15
|
-
if !SKIPPED_METADATA_KEYS.include?(key) && respond_to?("#{key}=")
|
16
|
-
send("#{key}=", value)
|
17
|
-
end
|
8
|
+
if (matches = contents.match(/^(-{3}\n.*?\n?)^(-{3}*$\n?)/m))
|
9
|
+
metadata = Hashie.symbolize_keys(YAML.safe_load(matches[1]))
|
10
|
+
contents = matches.post_match.strip
|
11
|
+
else
|
12
|
+
metadata = {}
|
18
13
|
end
|
19
14
|
|
20
|
-
|
15
|
+
[contents, metadata]
|
21
16
|
end
|
22
17
|
end
|
23
18
|
end
|
data/lib/dimples/page.rb
CHANGED
@@ -1,67 +1,73 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Dimples
|
4
|
-
# A class that models a single site page.
|
5
4
|
class Page
|
6
5
|
include Frontable
|
7
|
-
include Renderable
|
8
6
|
|
9
|
-
attr_accessor :path
|
10
|
-
attr_accessor :title
|
11
|
-
attr_accessor :filename
|
12
|
-
attr_accessor :extension
|
13
|
-
attr_accessor :layout
|
14
7
|
attr_accessor :contents
|
15
|
-
attr_accessor :
|
8
|
+
attr_accessor :metadata
|
9
|
+
attr_accessor :path
|
16
10
|
|
17
11
|
def initialize(site, path = nil)
|
18
12
|
@site = site
|
19
|
-
@extension = 'html'
|
20
13
|
@path = path
|
21
14
|
|
22
15
|
if @path
|
23
|
-
@
|
24
|
-
@output_directory = File.dirname(@path).sub(
|
25
|
-
@site.source_paths[:pages],
|
26
|
-
@site.output_paths[:site]
|
27
|
-
)
|
28
|
-
|
29
|
-
read_with_front_matter
|
16
|
+
@contents, @metadata = read_with_front_matter(@path)
|
30
17
|
else
|
31
|
-
@filename = 'index'
|
32
18
|
@contents = ''
|
33
|
-
@
|
19
|
+
@metadata = {}
|
34
20
|
end
|
35
21
|
end
|
36
22
|
|
37
|
-
def
|
38
|
-
|
23
|
+
def filename
|
24
|
+
@metadata[:filename] || 'index'
|
39
25
|
end
|
40
26
|
|
41
|
-
def
|
42
|
-
|
27
|
+
def extension
|
28
|
+
@metadata[:extension] || 'html'
|
43
29
|
end
|
44
30
|
|
45
|
-
def
|
46
|
-
|
31
|
+
def render(context = {})
|
32
|
+
metadata = @metadata.dup
|
33
|
+
metadata.merge!(context[:page]) if context[:page]
|
47
34
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
url.concat(output_filename) if filename != 'index'
|
52
|
-
end
|
35
|
+
context[:page] = Hashie::Mash.new(metadata)
|
36
|
+
|
37
|
+
renderer.render(context)
|
53
38
|
end
|
54
39
|
|
55
|
-
def write(context = {})
|
56
|
-
FileUtils.mkdir_p(
|
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
|
+
|
57
44
|
File.write(output_path, render(context))
|
58
45
|
rescue SystemCallError => e
|
59
|
-
|
60
|
-
raise Errors::PublishingError, error_message
|
46
|
+
raise PublishingError, "Failed to publish file at #{output_path} (#{e})"
|
61
47
|
end
|
62
48
|
|
63
49
|
def inspect
|
64
|
-
"#<#{self.class} @
|
50
|
+
"#<#{self.class} @path=#{path}>"
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def renderer
|
56
|
+
@renderer ||= Renderer.new(@site, self)
|
57
|
+
end
|
58
|
+
|
59
|
+
def method_missing(method_name, *args, &block)
|
60
|
+
if @metadata.key?(method_name)
|
61
|
+
@metadata[method_name]
|
62
|
+
elsif (matches = method_name.match(/([a-z_]+)=/))
|
63
|
+
@metadata[matches[1].to_sym] = args[0]
|
64
|
+
else
|
65
|
+
super
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def respond_to_missing?(method_name, include_private = false)
|
70
|
+
@metadata.key?(method_name) || method_name.match?(/([a-z_]+)=/) || super
|
65
71
|
end
|
66
72
|
end
|
67
73
|
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dimples
|
4
|
+
class Pager
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
attr_reader :current_page
|
8
|
+
attr_reader :previous_page
|
9
|
+
attr_reader :next_page
|
10
|
+
attr_reader :page_count
|
11
|
+
attr_reader :item_count
|
12
|
+
|
13
|
+
def initialize(url, posts, options = {})
|
14
|
+
@url = url
|
15
|
+
@posts = posts
|
16
|
+
@per_page = options[:per_page] || 10
|
17
|
+
@page_prefix = options[:page_prefix] || 'page'
|
18
|
+
@page_count = (posts.length.to_f / @per_page.to_i).ceil
|
19
|
+
|
20
|
+
step_to(1)
|
21
|
+
end
|
22
|
+
|
23
|
+
def each(&block)
|
24
|
+
(1..@page_count).each do |index|
|
25
|
+
block.yield step_to(index)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def step_to(page)
|
30
|
+
@current_page = (1..@page_count).cover?(page) ? page : 1
|
31
|
+
@previous_page = (@current_page - 1).positive? ? @current_page - 1 : nil
|
32
|
+
@next_page = @current_page + 1 <= @page_count ? @current_page + 1 : nil
|
33
|
+
|
34
|
+
@current_page
|
35
|
+
end
|
36
|
+
|
37
|
+
def posts_at(page)
|
38
|
+
@posts.slice((page - 1) * @per_page, @per_page)
|
39
|
+
end
|
40
|
+
|
41
|
+
def current_page_url
|
42
|
+
@current_page != 1 ? "#{@url}#{@page_prefix}#{@current_page}" : @url
|
43
|
+
end
|
44
|
+
|
45
|
+
def first_page_url
|
46
|
+
@url
|
47
|
+
end
|
48
|
+
|
49
|
+
def last_page_url
|
50
|
+
@page_count != 1 ? "#{@url}#{@page_prefix}#{@page_count}" : @url
|
51
|
+
end
|
52
|
+
|
53
|
+
def previous_page_url
|
54
|
+
return unless @previous_page
|
55
|
+
@previous_page != 1 ? "#{@url}#{@page_prefix}#{@previous_page}" : @url
|
56
|
+
end
|
57
|
+
|
58
|
+
def next_page_url
|
59
|
+
"#{@url}#{@page_prefix}#{@next_page}" if @next_page
|
60
|
+
end
|
61
|
+
|
62
|
+
def to_context
|
63
|
+
Hashie::Mash.new(
|
64
|
+
posts: posts_at(current_page),
|
65
|
+
current_page: @current_page,
|
66
|
+
page_count: @page_count,
|
67
|
+
post_count: @posts.count,
|
68
|
+
previous_page: @previous_page,
|
69
|
+
next_page: @next_page,
|
70
|
+
urls: {
|
71
|
+
current_page: current_page_url,
|
72
|
+
first_page: first_page_url,
|
73
|
+
last_page: last_page_url,
|
74
|
+
previous_page: previous_page_url,
|
75
|
+
next_page: next_page_url
|
76
|
+
}
|
77
|
+
)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|