aardi 0.9.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 +7 -0
- data/lib/aardi/abstract_blog.rb +27 -0
- data/lib/aardi/abstract_feed.rb +32 -0
- data/lib/aardi/abstract_page_support.rb +20 -0
- data/lib/aardi/archive.rb +48 -0
- data/lib/aardi/atom_feed.rb +58 -0
- data/lib/aardi/blog.rb +50 -0
- data/lib/aardi/config.rb +21 -0
- data/lib/aardi/content.rb +17 -0
- data/lib/aardi/content_hashes.rb +39 -0
- data/lib/aardi/custom_renderer.rb +43 -0
- data/lib/aardi/day.rb +44 -0
- data/lib/aardi/file_target.rb +43 -0
- data/lib/aardi/folder.rb +41 -0
- data/lib/aardi/home.rb +51 -0
- data/lib/aardi/init_files/config.yml +26 -0
- data/lib/aardi/json_feed.rb +32 -0
- data/lib/aardi/ledger.rb +15 -0
- data/lib/aardi/month.rb +48 -0
- data/lib/aardi/orphanage.rb +15 -0
- data/lib/aardi/page.rb +25 -0
- data/lib/aardi/page_content.rb +21 -0
- data/lib/aardi/page_target.rb +16 -0
- data/lib/aardi/path_servlet.rb +18 -0
- data/lib/aardi/post.rb +56 -0
- data/lib/aardi/site.rb +68 -0
- data/lib/aardi/sitemap.rb +56 -0
- data/lib/aardi/tasks/fixtimes.rake +8 -0
- data/lib/aardi/tasks/homepage.rake +6 -0
- data/lib/aardi/tasks/init.rake +34 -0
- data/lib/aardi/tasks/load_config.rake +7 -0
- data/lib/aardi/tasks/new.rake +16 -0
- data/lib/aardi/tasks/now.rake +6 -0
- data/lib/aardi/tasks/recent.rake +6 -0
- data/lib/aardi/tasks/render.rake +6 -0
- data/lib/aardi/tasks/server.rake +18 -0
- data/lib/aardi/tasks.rb +5 -0
- data/lib/aardi/template.rb +41 -0
- data/lib/aardi/timekeeper.rb +53 -0
- data/lib/aardi/version.rb +5 -0
- data/lib/aardi/year.rb +46 -0
- data/lib/aardi.rb +54 -0
- metadata +274 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 6ee9071fced8c74f53967ad02aad285eb7d0f2604c6491531013110838df516e
|
|
4
|
+
data.tar.gz: f398bf6a84c066b43a86f29ebad0055c8b2d4a8d706f0e43769e6c2ebbec7523
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: d29b6326aacdecdebec15c45c2023bc3d10eec76e2a10fff2cc57604b9888c82a7e515cbd07e7e274c78dd787c39854d8dcc0b6a295164996e21526e1aad32b4
|
|
7
|
+
data.tar.gz: 6e2c8fa1284906984e908968aae84bf3a5757da235e94ffe1856a95db1aac935505259e35d3db1c6a2fab74036eff57095050cf1be2eb54ebc7a5fc9b5c6d171
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aardi
|
|
4
|
+
class AbstractBlog
|
|
5
|
+
attr_reader :key
|
|
6
|
+
|
|
7
|
+
def metadata = (@metadata ||= {})
|
|
8
|
+
|
|
9
|
+
def mtime = children.max_by(&:mtime)&.mtime
|
|
10
|
+
|
|
11
|
+
def render
|
|
12
|
+
children.each(&:render)
|
|
13
|
+
write_target
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def children
|
|
19
|
+
[]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def write_target
|
|
23
|
+
source = PageContent.new content, title, metadata
|
|
24
|
+
PageTarget.new(source, target_path).write
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aardi
|
|
4
|
+
class AbstractFeed < AbstractBlog
|
|
5
|
+
def initialize(posts)
|
|
6
|
+
@posts = posts
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def render
|
|
10
|
+
write_target
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def target_path = "./#{feed_file}"
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def children
|
|
18
|
+
@posts
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def creation = children.max_by(&:creation)&.creation
|
|
22
|
+
|
|
23
|
+
def feed_url = "#{Aardi.config[:site_url]}/#{feed_file}"
|
|
24
|
+
|
|
25
|
+
def updated = children.max_by(&:updated)&.updated
|
|
26
|
+
|
|
27
|
+
def write_target
|
|
28
|
+
source = Content.new(content)
|
|
29
|
+
FileTarget.new(source, target_path).write
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aardi
|
|
4
|
+
module AbstractPageSupport
|
|
5
|
+
attr_reader :metadata, :mtime
|
|
6
|
+
|
|
7
|
+
def parse_source(path)
|
|
8
|
+
File.open(path, encoding: "utf-8") do |file|
|
|
9
|
+
parts = file.read.rpartition("\n----\n")
|
|
10
|
+
@metadata = YAML.safe_load(parts.first, permitted_classes: [Time]) || {}
|
|
11
|
+
@src_content = parts.last
|
|
12
|
+
@mtime = file.mtime.utc
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def title
|
|
17
|
+
metadata["Title"] || @src_content.split("\n").first.sub(/^#+ /, "")
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aardi
|
|
4
|
+
class Archive < AbstractBlog
|
|
5
|
+
def initialize(posts, archive_path)
|
|
6
|
+
@posts = posts
|
|
7
|
+
@archive_path = archive_path
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def content
|
|
11
|
+
year_fmt = "| %<year>s | %<months>s \n"
|
|
12
|
+
month_fmt = "[ %<count>s ](#{Aardi.config[:site_url]}/%<archive_path>s/%<year>s/%<month>s/)"
|
|
13
|
+
|
|
14
|
+
"#{header}#{years.map { |year| year.archive_row(year_fmt, month_fmt) }.join}"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def target_path = "./#{@archive_path}/index.html"
|
|
18
|
+
|
|
19
|
+
def title = Aardi.config[:blog_archive_title]
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def calendar
|
|
24
|
+
index = Hash.new { |hash, year| hash[year] = Year.new(year, @archive_path) }
|
|
25
|
+
@posts.each do |post|
|
|
26
|
+
index[post.year] << post
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
index
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def children
|
|
33
|
+
years
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def header
|
|
37
|
+
"# #{Aardi.config[:blog_archive_title]}
|
|
38
|
+
|
|
39
|
+
||Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec|
|
|
40
|
+
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
41
|
+
"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def years
|
|
45
|
+
@years ||= calendar.values.sort_by { |date| -date.key }
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aardi
|
|
4
|
+
class ATOMFeed < AbstractFeed
|
|
5
|
+
def content
|
|
6
|
+
atom_feed = Nokogiri::XML::Builder.new(encoding: "UTF-8") do
|
|
7
|
+
feed("xmlns" => "http://www.w3.org/2005/Atom") do |feed|
|
|
8
|
+
feed_details(feed)
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
atom_feed.to_xml
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# :reek:TooManyStatements
|
|
16
|
+
def feed_details(feed)
|
|
17
|
+
aardi_config = Aardi.config
|
|
18
|
+
|
|
19
|
+
feed.author do
|
|
20
|
+
name(aardi_config[:site_author])
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
subnodes = {id: feed_url, link: {href: feed_url, rel: "self"},
|
|
24
|
+
title: aardi_config[:site_title], updated: updated.iso8601}
|
|
25
|
+
|
|
26
|
+
subnodes.each do |node, value|
|
|
27
|
+
feed.public_send node, value
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
@posts.each do |post|
|
|
31
|
+
post_details(post, feed)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def feed_file
|
|
38
|
+
"index.xml"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# :reek:FeatureEnvy
|
|
42
|
+
# :reek:TooManyStatements
|
|
43
|
+
def post_details(post, feed)
|
|
44
|
+
feed.entry do
|
|
45
|
+
post_url = post.url
|
|
46
|
+
|
|
47
|
+
# For safety, must use content_ and not content:
|
|
48
|
+
content_(post.feed_snippet).type = "html"
|
|
49
|
+
|
|
50
|
+
subnodes = {id: post_url, link: {href: post_url}, title: post.title,
|
|
51
|
+
published: post.creation.iso8601, updated: post.updated.iso8601}
|
|
52
|
+
subnodes.each do |node, value|
|
|
53
|
+
feed.public_send node, value
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
data/lib/aardi/blog.rb
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aardi
|
|
4
|
+
class Blog < AbstractBlog
|
|
5
|
+
def initialize(posts_path, archive_path)
|
|
6
|
+
@posts_path = posts_path
|
|
7
|
+
@archive_path = archive_path
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def posts
|
|
11
|
+
@posts ||= Dir.glob("#{@posts_path}/**/*.md").map { |post_path| Post.new(post_path) }.sort_by(&:creation)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def report_recent
|
|
15
|
+
recent_posts(:blog_recent_posts).each(&:report_field_summary)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def archive
|
|
21
|
+
Archive.new(posts, @archive_path)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def atom_feed
|
|
25
|
+
ATOMFeed.new(feed_posts)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def children
|
|
29
|
+
[archive, home, atom_feed, json_feed]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def feed_posts
|
|
33
|
+
recent_posts(:blog_feed_posts)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def home
|
|
37
|
+
Home.new(recent_posts(:blog_home_posts), @archive_path)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def json_feed
|
|
41
|
+
JSONFeed.new(feed_posts)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def recent_posts(conf_key)
|
|
45
|
+
posts.last(Aardi.config[conf_key]).reverse
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def write_target = nil
|
|
49
|
+
end
|
|
50
|
+
end
|
data/lib/aardi/config.rb
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aardi
|
|
4
|
+
class Config
|
|
5
|
+
def initialize
|
|
6
|
+
@data = {}
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def [](key) = @data[key]
|
|
10
|
+
|
|
11
|
+
# :reek:TooManyStatements
|
|
12
|
+
def load(path)
|
|
13
|
+
config_hash = YAML.safe_load_file(path)
|
|
14
|
+
config_hash.transform_keys!(&:to_sym)
|
|
15
|
+
config_hash[:markup_options]&.transform_keys!(&:to_sym)
|
|
16
|
+
@data.merge!(config_hash)
|
|
17
|
+
@data.freeze
|
|
18
|
+
self
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aardi
|
|
4
|
+
class Content
|
|
5
|
+
def initialize(src_content)
|
|
6
|
+
@src_content = src_content.strip
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def output
|
|
10
|
+
@output ||= @src_content
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def output_hash
|
|
14
|
+
@output_hash ||= Zlib.crc32(output)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aardi
|
|
4
|
+
class ContentHashes
|
|
5
|
+
def initialize(path)
|
|
6
|
+
@path = path
|
|
7
|
+
read_hashes
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def [](path)
|
|
11
|
+
@hashes[path]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def []=(path, hash)
|
|
15
|
+
@hashes[path] = hash
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def write
|
|
19
|
+
return if new_hashes == @original_hashes
|
|
20
|
+
|
|
21
|
+
File.write(@path, @new_hashes)
|
|
22
|
+
puts "Wrote: #{@path}\n"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def new_hashes
|
|
28
|
+
@new_hashes ||= @hashes.sort.map! { |path, hash| "#{path}: #{hash}\n" }.join
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def read_hashes
|
|
32
|
+
@original_hashes = File.exist?(@path) ? File.read(@path) : ""
|
|
33
|
+
@hashes = @original_hashes.split("\n").to_h do |line|
|
|
34
|
+
path, hash = line.split(":", 2)
|
|
35
|
+
[path.strip, hash.to_i]
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aardi
|
|
4
|
+
class CustomRenderer < Redcarpet::Render::HTML
|
|
5
|
+
include Redcarpet::Render::SmartyPants
|
|
6
|
+
|
|
7
|
+
HEADER_SQUEEZE = /&#.*?;|"|[^a-z0-9\-_]/
|
|
8
|
+
|
|
9
|
+
def header(text, header_level)
|
|
10
|
+
squeezed_text = text.squeeze(" ")
|
|
11
|
+
id = header_id(text)
|
|
12
|
+
"<h#{header_level} id=\"#{id}\">#{squeezed_text}</h#{header_level}>"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def link(link, title, content)
|
|
16
|
+
link_title = " title=\"#{title}\"" if title
|
|
17
|
+
"<a href=\"#{link}\"#{link_title}>#{content}</a>"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def reset
|
|
21
|
+
ids.clear
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def header_id(text)
|
|
27
|
+
stub_id = header_stub_id(text)
|
|
28
|
+
count = ids[stub_id] += 1
|
|
29
|
+
|
|
30
|
+
return "#{stub_id}-#{count - 1}" if count > 1
|
|
31
|
+
|
|
32
|
+
stub_id
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def header_stub_id(text)
|
|
36
|
+
text.downcase.strip.tr(" ", "-").gsub(HEADER_SQUEEZE, "").squeeze("-")
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def ids
|
|
40
|
+
@ids ||= Hash.new(0)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
data/lib/aardi/day.rb
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aardi
|
|
4
|
+
# :reek:TooManyInstanceVariables
|
|
5
|
+
class Day < AbstractBlog
|
|
6
|
+
def initialize(year, month, key, archive_path)
|
|
7
|
+
@year = year
|
|
8
|
+
@month = month
|
|
9
|
+
@key = key
|
|
10
|
+
@archive_path = archive_path
|
|
11
|
+
@posts = []
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def <<(post)
|
|
15
|
+
@posts << post
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def content
|
|
19
|
+
@content ||= begin
|
|
20
|
+
sorted_posts = @posts.sort_by(&:creation)
|
|
21
|
+
posts_content = sorted_posts.reverse!.map!(&:content)
|
|
22
|
+
"# #{title}\n#{posts_content.join}"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def count = @posts.count
|
|
27
|
+
|
|
28
|
+
def target_path
|
|
29
|
+
"./#{@archive_path}/#{@year}/#{@month}/#{self}/index.html"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def title = date.strftime("%A, %-e %B %Y")
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def children
|
|
37
|
+
@posts
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def date = Date.new(@year.key, @month.key, @key)
|
|
41
|
+
|
|
42
|
+
def to_s = @key.to_s.rjust(2, "0")
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aardi
|
|
4
|
+
class FileTarget
|
|
5
|
+
def initialize(src, target_path)
|
|
6
|
+
@src = src
|
|
7
|
+
@path = target_path
|
|
8
|
+
@content_hashes = Aardi.ledger[:content_hashes]
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# :reek:TooManyStatements
|
|
12
|
+
def write
|
|
13
|
+
do_write = should_write?
|
|
14
|
+
update_hash
|
|
15
|
+
return unless do_write
|
|
16
|
+
|
|
17
|
+
FileUtils.mkdir_p(File.dirname(@path))
|
|
18
|
+
File.write(@path, "#{@src.output}\n")
|
|
19
|
+
puts("Wrote #{@path}")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def file_exists?
|
|
25
|
+
File.exist? @path
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def output_hash_changed?
|
|
29
|
+
@src.output_hash != @content_hashes[@path]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def should_write?
|
|
33
|
+
return true unless file_exists?
|
|
34
|
+
return false unless output_hash_changed?
|
|
35
|
+
|
|
36
|
+
@src.output != File.read(@path).strip
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def update_hash
|
|
40
|
+
@content_hashes[@path] = @src.output_hash
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
data/lib/aardi/folder.rb
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aardi
|
|
4
|
+
class Folder
|
|
5
|
+
def initialize(path)
|
|
6
|
+
@path = path
|
|
7
|
+
@normalized_path = "#{path.sub(/^\./, "")}/"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def mtime = children.max_by(&:mtime).mtime
|
|
11
|
+
|
|
12
|
+
def render
|
|
13
|
+
children.each(&:render)
|
|
14
|
+
|
|
15
|
+
update_sitemap if Aardi.config[:sitemap_entries][@normalized_path]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def children
|
|
21
|
+
sources + folders
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def folders
|
|
25
|
+
@folders ||= paths.filter_map { |path| Folder.new(path) if File.directory?(path) }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def paths
|
|
29
|
+
@paths ||= FileList["#{@path}/*"].exclude(Aardi.config[:files_to_exclude])
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def sources
|
|
33
|
+
@sources ||= paths.filter_map { |path| Page.new(path) if path.end_with?(".md") }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def update_sitemap
|
|
37
|
+
# '.' is the top level so skip it since the homepage will register itself
|
|
38
|
+
Aardi.ledger[:sitemap].update_mtime(@normalized_path, mtime) unless @path == "."
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
data/lib/aardi/home.rb
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aardi
|
|
4
|
+
class Home < AbstractBlog
|
|
5
|
+
def initialize(posts, archive_path)
|
|
6
|
+
@posts = posts
|
|
7
|
+
@archive_path = archive_path
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def content
|
|
11
|
+
"# #{title}\n#{post_days_content}#{content_footer}"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def render
|
|
15
|
+
Aardi.ledger[:sitemap].update_mtime("/", mtime)
|
|
16
|
+
write_target
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def target_path = "./index.html"
|
|
20
|
+
|
|
21
|
+
def title = Aardi.config[:blog_home_title]
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def children
|
|
26
|
+
@posts
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def content_footer
|
|
30
|
+
site_url = Aardi.config[:site_url]
|
|
31
|
+
more_archive = "[Archive](#{site_url}/#{@archive_path}/)"
|
|
32
|
+
more_rss = "[RSS](#{site_url}/index.xml)"
|
|
33
|
+
more_json = "[JSON](#{site_url}/index.json)"
|
|
34
|
+
"**More:** #{more_archive}, #{more_rss}, #{more_json}"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def days_hash
|
|
38
|
+
@days_hash ||= @posts.group_by { |post| post.creation.strftime("%Y-%m-%d") }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def post_day_content(post_day)
|
|
42
|
+
date_header = post_day.first.creation.strftime("%A, %e %B %Y")
|
|
43
|
+
posts_content = post_day.map(&:content).join
|
|
44
|
+
"## #{date_header}\n#{posts_content}"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def post_days_content
|
|
48
|
+
days_hash.values.map { |day| post_day_content(day) }.join
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
site_title: My Site
|
|
2
|
+
site_url: http://localhost:8000
|
|
3
|
+
site_author: Author Name
|
|
4
|
+
files_to_exclude:
|
|
5
|
+
- ./blog
|
|
6
|
+
- ./posts
|
|
7
|
+
ignore_orphans: []
|
|
8
|
+
template_path: .template.html
|
|
9
|
+
blog_archive_path: blog
|
|
10
|
+
blog_posts_path: posts
|
|
11
|
+
blog_feed_posts: 10
|
|
12
|
+
blog_recent_posts: 10
|
|
13
|
+
blog_archive_title: Blog Archive
|
|
14
|
+
blog_home_title: My Site
|
|
15
|
+
blog_home_posts: 10
|
|
16
|
+
sitemap_entries:
|
|
17
|
+
/: daily
|
|
18
|
+
markup_options:
|
|
19
|
+
autolink: false
|
|
20
|
+
fenced_code_blocks: true
|
|
21
|
+
footnotes: true
|
|
22
|
+
no_intra_emphasis: true
|
|
23
|
+
strikethrough: true
|
|
24
|
+
superscript: true
|
|
25
|
+
tables: true
|
|
26
|
+
content_hashes_path: .content_hashes.txt
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aardi
|
|
4
|
+
class JSONFeed < AbstractFeed
|
|
5
|
+
def content
|
|
6
|
+
aardi_config = Aardi.config
|
|
7
|
+
feed_content = {version: "https://jsonfeed.org/version/1.1", title: aardi_config[:site_title],
|
|
8
|
+
home_page_url: aardi_config[:site_url], feed_url:}
|
|
9
|
+
feed_content[:items] = @posts.map { |post| post_details(post) }
|
|
10
|
+
|
|
11
|
+
JSON.pretty_generate(feed_content)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def feed_file
|
|
17
|
+
"index.json"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def post_details(post)
|
|
21
|
+
post_updated = post.updated
|
|
22
|
+
post_creation = post.creation
|
|
23
|
+
|
|
24
|
+
details = {id: post.name, url: post.url, title: post.title,
|
|
25
|
+
date_published: post_creation.iso8601, content_html: post.feed_snippet}
|
|
26
|
+
|
|
27
|
+
details[:date_modified] = post_updated.iso8601 unless post_creation == post_updated
|
|
28
|
+
|
|
29
|
+
details.compact
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
data/lib/aardi/ledger.rb
ADDED
data/lib/aardi/month.rb
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aardi
|
|
4
|
+
class Month < AbstractBlog
|
|
5
|
+
def initialize(year, key, archive_path)
|
|
6
|
+
@year = year
|
|
7
|
+
@key = key
|
|
8
|
+
@archive_path = archive_path
|
|
9
|
+
@index = Hash.new { |hash, day| hash[day] = Day.new(year, self, day, archive_path) }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def <<(post)
|
|
13
|
+
@index[post.day] << post
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def archive_cell(month_fmt)
|
|
17
|
+
cell = count.zero? ? "" : format(month_fmt, count:, archive_path: @archive_path, year: @year, month: self)
|
|
18
|
+
"#{cell} |"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def content
|
|
22
|
+
@content ||= begin
|
|
23
|
+
days_content = days.map { |day| "##{day.content}" }.join
|
|
24
|
+
"# #{title}\n#{days_content}"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def count = days.sum(&:count)
|
|
29
|
+
|
|
30
|
+
def target_path
|
|
31
|
+
"./#{@archive_path}/#{@year}/#{self}/index.html"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def title = Date.new(@year.key, @key).strftime("%B %Y")
|
|
35
|
+
|
|
36
|
+
def to_s = @key.to_s.rjust(2, "0")
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def children
|
|
41
|
+
days
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def days
|
|
45
|
+
@days ||= @index.values.sort_by { |value| -value.key }
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aardi
|
|
4
|
+
class Orphanage
|
|
5
|
+
def warn
|
|
6
|
+
Aardi.ledger[:html_files].each { |path| puts("Orphan: #{path}") unless ignored?(path) }
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
def ignored?(path)
|
|
12
|
+
Aardi.config[:ignore_orphans].any? { |prefix| path.start_with?(prefix) }
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|