den 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/den +72 -0
- data/den.gemspec +20 -0
- data/lib/den/examples.rb +25 -0
- data/lib/den/page.rb +41 -0
- data/lib/den/post.rb +62 -0
- data/lib/den/resource.rb +58 -0
- data/lib/den/template.rb +101 -0
- data/lib/den/utilities.rb +19 -0
- data/lib/den.rb +322 -0
- metadata +54 -0
data/bin/den
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
|
4
|
+
|
5
|
+
require 'den'
|
6
|
+
require 'yaml'
|
7
|
+
|
8
|
+
# If the command was to make a new site, do it and quit
|
9
|
+
if "#{ARGV[0]} #{ARGV[1]}".downcase == "new site" and ARGV.length == 3
|
10
|
+
Den.create_skeleton(ARGV[2])
|
11
|
+
exit
|
12
|
+
end
|
13
|
+
|
14
|
+
# Exit if the '.den' file doesn't exist
|
15
|
+
if !File.exists?('.den')
|
16
|
+
abort("Make sure you're running from the root of your Den instance.")
|
17
|
+
end
|
18
|
+
|
19
|
+
# Load the config if it exists
|
20
|
+
config = YAML::load(File.open('config.yml')) if File.exist?('config.yml')
|
21
|
+
|
22
|
+
# Create a Den instance
|
23
|
+
den = Den.new(config=config)
|
24
|
+
|
25
|
+
# Process arguments
|
26
|
+
case ARGV[0]
|
27
|
+
|
28
|
+
when 'new'
|
29
|
+
# Handle different 'new' cases (page, post)
|
30
|
+
if ARGV[1].downcase == 'page'
|
31
|
+
if !(ARGV.length == 3 or ARGV.length == 4)
|
32
|
+
abort('Invalid format for "new page".')
|
33
|
+
end
|
34
|
+
den.new_resource('page', :dest => ARGV[2], :file => ARGV[3])
|
35
|
+
elsif ARGV[1].downcase == 'post'
|
36
|
+
if !(ARGV.length == 2 or ARGV.length == 3)
|
37
|
+
abort('Invalid format for "new post".')
|
38
|
+
end
|
39
|
+
den.new_resource('post', :file => ARGV[2])
|
40
|
+
else
|
41
|
+
abort("'#{ARGV[1]}' is an invalid argument for 'new'. Must be either 'page' or 'post'.")
|
42
|
+
end
|
43
|
+
|
44
|
+
# Update the site
|
45
|
+
den.update_site(refresh=true)
|
46
|
+
|
47
|
+
|
48
|
+
when 'delete'
|
49
|
+
abort('Invalid format for command "delete".') if ARGV.length != 3
|
50
|
+
if ARGV[1].downcase == 'page' or ARGV[1].downcase == 'post'
|
51
|
+
den.delete_resource(ARGV[1].downcase, ARGV[2])
|
52
|
+
else
|
53
|
+
abort("'#{ARGV[1]}' is an invalid argument for 'delete'. Must be either 'page' or 'post'.")
|
54
|
+
end
|
55
|
+
|
56
|
+
# Update the site
|
57
|
+
den.update_site(refresh=true)
|
58
|
+
|
59
|
+
|
60
|
+
when 'list'
|
61
|
+
abort('Invalid format for "list".') if ARGV.length > 1
|
62
|
+
# Display all the content
|
63
|
+
den.print_content
|
64
|
+
|
65
|
+
# Unrecognized argument, exit
|
66
|
+
else
|
67
|
+
if ARGV.length > 0
|
68
|
+
abort('Invalid command.')
|
69
|
+
else
|
70
|
+
den.update_site
|
71
|
+
end
|
72
|
+
end
|
data/den.gemspec
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'den'
|
3
|
+
s.version = '0.1.0'
|
4
|
+
s.summary = 'A really simple static-site generator.'
|
5
|
+
s.authors = ["Peter Valdez"]
|
6
|
+
s.email = 'peter@someindividual.com'
|
7
|
+
s.executables << 'den'
|
8
|
+
s.homepage = 'https://github.com/azlyth/den'
|
9
|
+
s.files = %w[
|
10
|
+
bin/den
|
11
|
+
lib/den/examples.rb
|
12
|
+
lib/den/page.rb
|
13
|
+
lib/den/post.rb
|
14
|
+
lib/den/resource.rb
|
15
|
+
lib/den/template.rb
|
16
|
+
lib/den/utilities.rb
|
17
|
+
lib/den.rb
|
18
|
+
den.gemspec
|
19
|
+
]
|
20
|
+
end
|
data/lib/den/examples.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# A module used to keep all the skeleton defaults in one place.
|
2
|
+
module Examples
|
3
|
+
CONFIG = ":site:\n :root: /var/www/\n :posts: musings\n"
|
4
|
+
|
5
|
+
TEMPLATES = {
|
6
|
+
# Base template
|
7
|
+
:base => "<html>\n <head>\n <title>{{ title }} | mysite</title>\n </head>\n <body>\n <div id=\"content\">\n {{ body }}\n </div>\n </body>\n</html>\n",
|
8
|
+
|
9
|
+
# Index template
|
10
|
+
:index => "{{ extends base.html }}\n\n{{ block title }}index{{ endblock }}\n\n{{ block body }}\n[[ body ]]\n{{ endblock }}\n",
|
11
|
+
|
12
|
+
# Page template
|
13
|
+
:page => "{{ extends base.html }}\n\n{{ block title }}[[ title ]]{{ endblock }}\n\n{{ block body }}\n[[ content ]]\n{{ endblock }}\n",
|
14
|
+
|
15
|
+
# Post template
|
16
|
+
:post => "{{ extends base.html }}\n\n{{ block title }}[[ title ]]{{ endblock }}\n\n{{ block body }}\n[[ content ]]\n{{ endblock }}\n",
|
17
|
+
}
|
18
|
+
|
19
|
+
# Example page
|
20
|
+
PAGE = "[About me]\n\nThis is a test \"about me\" page.\nAsdfasdf.\n\n# Intro\n\n## Past\n\nBlah blah, I did this and that.\n\n## Now\n\nWoah, you do WHAT these days?\n"
|
21
|
+
|
22
|
+
# Example post
|
23
|
+
POST = "[What a post.]\n\nNo, but really, what a post. I'm kidding this is an example post.\nIt's a post that makes a world of a difference.\n\n# Some great point\n\n## A worthy subpoint\n\nAnd some info.\n\nAnd conclude.\n"
|
24
|
+
|
25
|
+
end
|
data/lib/den/page.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require "cgi"
|
2
|
+
require "den/resource"
|
3
|
+
|
4
|
+
class Page < Resource
|
5
|
+
|
6
|
+
def to_s
|
7
|
+
"Page: #{@content[:id]}"
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
# Return the HTML rendering of this page
|
12
|
+
def html()
|
13
|
+
_html = "<div id=\"page\">\n"
|
14
|
+
|
15
|
+
# Wrap title in anchor if link is provided
|
16
|
+
_html += "<h1 id=\"title\">#{@content[:title]}</h1>\n"
|
17
|
+
|
18
|
+
# Add the rest of the necessary content
|
19
|
+
_html += "<div id=\"body\">\n" +
|
20
|
+
"#{@content[:body]}\n" +
|
21
|
+
"</div>" +
|
22
|
+
"</div>"
|
23
|
+
|
24
|
+
_html
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
# Pull out metadata and markup the page
|
29
|
+
def process
|
30
|
+
File.open(@file) do |f|
|
31
|
+
page = markup(f.read)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Extract the url from the filename
|
35
|
+
page[:id] = @file.split('/')[-1]
|
36
|
+
|
37
|
+
# Store the processed info
|
38
|
+
@content = page
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
data/lib/den/post.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require "date"
|
2
|
+
require "cgi"
|
3
|
+
require "den/resource"
|
4
|
+
|
5
|
+
class Post < Resource
|
6
|
+
|
7
|
+
def to_s
|
8
|
+
"Post #{@content[:id]}"
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
def [](index)
|
13
|
+
@content[index]
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
# Return the HTML rendering of the post
|
18
|
+
def html(link="")
|
19
|
+
_html = "<div id=\"post\">\n"
|
20
|
+
|
21
|
+
# Wrap title in anchor if link is provided
|
22
|
+
_html += "<h1 id=\"title\">"
|
23
|
+
if link != ""
|
24
|
+
_html += "<a href=\"#{link}\">"
|
25
|
+
end
|
26
|
+
_html += "#{@content[:title]}"
|
27
|
+
if link != ""
|
28
|
+
_html += "</a>"
|
29
|
+
end
|
30
|
+
|
31
|
+
_html += "</h1>\n"
|
32
|
+
|
33
|
+
|
34
|
+
# Add the rest of the necessary content
|
35
|
+
_html += "<h2 id=\"date\">#{@content[:date].strftime("%B %e, %Y")}</h2>\n" +
|
36
|
+
"<div id=\"body\">\n" +
|
37
|
+
"#{@content[:body]}\n" +
|
38
|
+
"</div>\n" +
|
39
|
+
"</div>"
|
40
|
+
|
41
|
+
_html
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
# Pull out metadata and markup the post
|
46
|
+
def process
|
47
|
+
File.open(@file) do |f|
|
48
|
+
# Extract the date
|
49
|
+
post = {
|
50
|
+
:id => f.readline.chomp,
|
51
|
+
:date => DateTime.strptime(f.readline.chomp, "%Y-%m-%d %H:%M:%S %z")
|
52
|
+
}
|
53
|
+
|
54
|
+
# Process the post
|
55
|
+
post.merge!(markup(f.read))
|
56
|
+
|
57
|
+
# Store the processed info
|
58
|
+
@content = post
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
data/lib/den/resource.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# General Den resource object (included by Page and Post)
|
2
|
+
class Resource
|
3
|
+
|
4
|
+
# Initialize the object
|
5
|
+
def initialize(file)
|
6
|
+
@file = file
|
7
|
+
process
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
def [](index)
|
12
|
+
@content[index]
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
# Deletes itself
|
17
|
+
def delete
|
18
|
+
File.delete(@file)
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
# General markup function
|
23
|
+
def markup(s)
|
24
|
+
s = CGI::escapeHTML(s)
|
25
|
+
title = nil
|
26
|
+
|
27
|
+
# Extract title
|
28
|
+
s.gsub!(/\A\[(.*\S)\]$/) do |x|
|
29
|
+
title = $1
|
30
|
+
""
|
31
|
+
end
|
32
|
+
|
33
|
+
# Remove duplicate newlines
|
34
|
+
s.gsub!(/\n\n+/, "\n\n")
|
35
|
+
|
36
|
+
# Remove leading whitespace from lines
|
37
|
+
s.gsub!(/^ +/, "")
|
38
|
+
|
39
|
+
# Pad string to remove edge cases
|
40
|
+
s.gsub!(/(\A\n*)|(\n*\z)/, "\n")
|
41
|
+
|
42
|
+
# Headers
|
43
|
+
s.gsub!(/^(#+)\s*(.*)/) {
|
44
|
+
len = $1.length
|
45
|
+
"<h#{len+1} class=\"header\">#$2</h#{len}>"
|
46
|
+
}
|
47
|
+
|
48
|
+
# Paragraphs
|
49
|
+
s.gsub!(/(\A|\n)\n([^<])/, "\n\n<p>\\2")
|
50
|
+
s.gsub!(/([^>])\n\n/, "\\1</p>\n\n")
|
51
|
+
|
52
|
+
# Remove extra newlines
|
53
|
+
s.gsub!(/\n+/, "\n")
|
54
|
+
|
55
|
+
{:title => title, :body => s}
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
data/lib/den/template.rb
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
class Template
|
2
|
+
|
3
|
+
def initialize(template_dir, template_file=nil, post_location=nil)
|
4
|
+
@template_dir = template_dir
|
5
|
+
load_template(template_file) if !template_file.nil?
|
6
|
+
@post_location = post_location
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
# Calls the appropriate render function
|
11
|
+
def render(obj, prev_page=nil, next_page=nil)
|
12
|
+
case obj
|
13
|
+
when Resource
|
14
|
+
return render_resource(obj)
|
15
|
+
when Array
|
16
|
+
return render_index(obj, prev_page, next_page)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
# Returns the HTML of a Resource
|
22
|
+
def render_resource(r)
|
23
|
+
data = {
|
24
|
+
"title" => r[:title],
|
25
|
+
"content" => r.html
|
26
|
+
}
|
27
|
+
|
28
|
+
populate(data)
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
# Returns the HTML of an index
|
33
|
+
def render_index(posts, prev_page, next_page)
|
34
|
+
# Get the HTML of each Post and combine them
|
35
|
+
posts.collect! { |p| p.html(File.join('/', @post_location, p[:id].to_s)) }
|
36
|
+
data = { "body" => posts.join("\n\n") }
|
37
|
+
|
38
|
+
# Append next/previous links if necessary
|
39
|
+
if !prev_page.nil?
|
40
|
+
data["body"] += "<a class=\"nav\" id=\"future\" href=\"#{prev_page}\">Newer Posts</a>\n"
|
41
|
+
end
|
42
|
+
|
43
|
+
if !next_page.nil?
|
44
|
+
data["body"] += "<a class=\"nav\" id=\"past\" href=\"#{next_page}\">Older Posts</a>\n"
|
45
|
+
end
|
46
|
+
|
47
|
+
# Return the rendered index
|
48
|
+
populate(data)
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
# Fills in the template with the data provided
|
53
|
+
def populate(data)
|
54
|
+
@content.gsub(/\[\[ (\S*) \]\]/) { |x| data[$1] }
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
# Loads the template file into @content
|
59
|
+
def load_template(filename)
|
60
|
+
template_path = File.join(@template_dir, filename)
|
61
|
+
|
62
|
+
if File.file?(template_path)
|
63
|
+
# Load the template file
|
64
|
+
template_file = ''
|
65
|
+
File.open(template_path) do |f|
|
66
|
+
template_file = f.read
|
67
|
+
end
|
68
|
+
|
69
|
+
# Check if this template is an extension
|
70
|
+
if template_file =~ /{{ extends (\S*) }}/
|
71
|
+
# Load the parent template into content
|
72
|
+
load_template($1)
|
73
|
+
|
74
|
+
# Find blocks
|
75
|
+
template_file = template_file.split("{{ endblock }}")
|
76
|
+
blocks = {}
|
77
|
+
for block in template_file
|
78
|
+
if /{{ block (?<label>\S*) }}(?<content>[\s\S]*)/ =~ block
|
79
|
+
blocks[label] = content
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Combine the parent template with the blocks
|
84
|
+
merge_templates(blocks)
|
85
|
+
else
|
86
|
+
# Load the file into content
|
87
|
+
@content = template_file
|
88
|
+
end
|
89
|
+
else
|
90
|
+
puts "Unable to locate template: #{@template_dir + filename}."
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Combine a template with its parent
|
95
|
+
def merge_templates(blocks)
|
96
|
+
@content.gsub!(/{{ (\S*) }}/) do |x|
|
97
|
+
blocks[$1]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Given a filename (and extension, optionally), returns an unused filename.
|
2
|
+
def get_unused_filename(filename, extension="")
|
3
|
+
extension = "." + extension if extension != ""
|
4
|
+
|
5
|
+
full_path = filename + extension
|
6
|
+
|
7
|
+
if File.exists?(full_path)
|
8
|
+
count = 1
|
9
|
+
|
10
|
+
# Keep adding to the count until we find filename that isn't taken.
|
11
|
+
while File.exists?("#{filename}_#{count}#{extension}")
|
12
|
+
count += 1
|
13
|
+
end
|
14
|
+
|
15
|
+
full_path = "#{filename}_#{count}#{extension}"
|
16
|
+
end
|
17
|
+
|
18
|
+
full_path
|
19
|
+
end
|
data/lib/den.rb
ADDED
@@ -0,0 +1,322 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
require "date"
|
3
|
+
require "den/post"
|
4
|
+
require "den/page"
|
5
|
+
require "den/template"
|
6
|
+
require "den/utilities"
|
7
|
+
require "den/examples"
|
8
|
+
|
9
|
+
class Den
|
10
|
+
|
11
|
+
# Creates a new Den site
|
12
|
+
def self.create_skeleton(location)
|
13
|
+
# Create the directories along with default templates
|
14
|
+
Dir.mkdir(location)
|
15
|
+
Dir.mkdir(File.join(location, 'pages'))
|
16
|
+
Dir.mkdir(File.join(location, 'posts'))
|
17
|
+
Dir.mkdir(File.join(location, 'posts', 'new'))
|
18
|
+
Dir.mkdir(File.join(location, 'templates'))
|
19
|
+
Examples::TEMPLATES.each_pair { |file, content|
|
20
|
+
File.open(File.join(location, 'templates', file.to_s + '.html'), 'w') do |f|
|
21
|
+
f.print(content)
|
22
|
+
end
|
23
|
+
}
|
24
|
+
|
25
|
+
File.open(File.join(location, 'config.yml'), 'w') do |f|
|
26
|
+
f.write(Examples::CONFIG)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Create the file that indicates this is a Den instance
|
30
|
+
FileUtils.touch(File.join(location, '.den'))
|
31
|
+
|
32
|
+
puts "Created new site in '#{location}'."
|
33
|
+
end
|
34
|
+
|
35
|
+
# Default configuration values
|
36
|
+
@@default_config = {
|
37
|
+
# Where pages are actually served from
|
38
|
+
# Note the following:
|
39
|
+
# - 'root' gets prepended to all locations but 'index'
|
40
|
+
# - 'posts' gets prepended to 'index'
|
41
|
+
:site => {
|
42
|
+
:root => "/var/www/",
|
43
|
+
:pages => "",
|
44
|
+
:posts => "posts/",
|
45
|
+
:index => "index/",
|
46
|
+
},
|
47
|
+
}
|
48
|
+
|
49
|
+
@@default_meta = {
|
50
|
+
# The number of total posts
|
51
|
+
:last_post => 0,
|
52
|
+
}
|
53
|
+
|
54
|
+
|
55
|
+
# Create the Den and store the config, prioritizing the provided one.
|
56
|
+
def initialize(config=nil)
|
57
|
+
@config = @@default_config
|
58
|
+
|
59
|
+
if !config.nil?
|
60
|
+
@config[:new_posts] = config[:new_posts] if !config[:new_posts].nil?
|
61
|
+
@config[:site].merge!(config[:site]) if !config[:site].nil?
|
62
|
+
end
|
63
|
+
|
64
|
+
load_metadata
|
65
|
+
gather_new_posts
|
66
|
+
prepare_content
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
|
71
|
+
|
72
|
+
# Update the site
|
73
|
+
def update_site(refresh=false)
|
74
|
+
if refresh
|
75
|
+
prepare_content
|
76
|
+
end
|
77
|
+
push_content
|
78
|
+
create_indices
|
79
|
+
puts "Updated the site."
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
# Display the Den's pages and posts, along with their metadata
|
84
|
+
def print_content
|
85
|
+
puts "Pages:" if !@pages.empty?
|
86
|
+
@pages.each do |p|
|
87
|
+
puts " #{p[:id]} (title: '#{p[:title]}')"
|
88
|
+
end
|
89
|
+
|
90
|
+
puts "Posts:" if !@posts.empty?
|
91
|
+
@posts.each do |p|
|
92
|
+
puts " #{p[:id]} (title: '#{p[:title]}', date: #{p[:date].strftime("%B %e, %Y")})"
|
93
|
+
end
|
94
|
+
|
95
|
+
if @pages.empty? and @posts.empty?
|
96
|
+
puts "No content."
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
# Adds a page or post. If a file is provided, it copies the contents of the
|
102
|
+
# file. Otherwise, it will start the default editor to make the new resource.
|
103
|
+
def new_resource(type, options)
|
104
|
+
defaults = {:file => nil, :dest => nil}
|
105
|
+
options = defaults.merge(options)
|
106
|
+
type.downcase!
|
107
|
+
|
108
|
+
if options[:file].nil?
|
109
|
+
# Create the new page/post with the default editor
|
110
|
+
if type == 'page'
|
111
|
+
file = File.join('pages', options[:dest])
|
112
|
+
system("/usr/bin/editor #{file}")
|
113
|
+
elsif type == 'post'
|
114
|
+
file = File.join('posts', 'new', 'new.post')
|
115
|
+
system("/usr/bin/editor #{file}")
|
116
|
+
gather_new_posts
|
117
|
+
end
|
118
|
+
|
119
|
+
if File.exists?(file)
|
120
|
+
puts "Added a #{type}."
|
121
|
+
else
|
122
|
+
puts "Cancelled adding a #{type}."
|
123
|
+
end
|
124
|
+
|
125
|
+
else
|
126
|
+
# Copy the file that will be the new page/post
|
127
|
+
if type == 'page'
|
128
|
+
FileUtils.cp(options[:file], File.join('pages', options[:dest]))
|
129
|
+
elsif type == 'post'
|
130
|
+
FileUtils.cp(options[:file], File.join('posts', 'new'))
|
131
|
+
gather_new_posts
|
132
|
+
end
|
133
|
+
|
134
|
+
puts "Using #{options[:file]} as a new #{type}."
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
|
139
|
+
# Deletes a page/post, identified by its ID
|
140
|
+
def delete_resource(type, id)
|
141
|
+
type.downcase!
|
142
|
+
|
143
|
+
# Find the page/post
|
144
|
+
if type == 'page'
|
145
|
+
res = @pages.select { |p| p[:id] == id }
|
146
|
+
fn = File.join(@config[:site][:root], @config[:site][:pages])
|
147
|
+
elsif type == 'post'
|
148
|
+
res = @posts.select { |p| p[:id] == id }
|
149
|
+
fn = File.join(@config[:site][:root], @config[:site][:posts])
|
150
|
+
end
|
151
|
+
|
152
|
+
# If we found a resource, delete it.
|
153
|
+
if !res.nil?
|
154
|
+
res = res[0]
|
155
|
+
fn = File.join(fn, res[:id])
|
156
|
+
File.delete(fn) if File.exists?(fn)
|
157
|
+
res.delete
|
158
|
+
puts "Deleted #{type} '#{id}'."
|
159
|
+
else
|
160
|
+
puts "No #{type} with id '#{id}'."
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
|
165
|
+
def load_metadata
|
166
|
+
@meta = @@default_meta
|
167
|
+
|
168
|
+
meta_file = File.join("metadata.yml")
|
169
|
+
|
170
|
+
# Load the metadata
|
171
|
+
if File.exists?(meta_file)
|
172
|
+
yml = YAML::load(File.open(meta_file))
|
173
|
+
@meta.merge!(yml)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
|
178
|
+
def save_metadata
|
179
|
+
meta_file = File.join("metadata.yml")
|
180
|
+
|
181
|
+
File.open(meta_file, 'w') do |f|
|
182
|
+
f.puts("# Do not touch this file, as it's auto-generated.")
|
183
|
+
YAML::dump(@meta, f)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
|
188
|
+
# Create the indices for the posts
|
189
|
+
def create_indices
|
190
|
+
destination = File.join(@config[:site][:root], @config[:site][:posts], @config[:site][:index])
|
191
|
+
Dir.mkdir(destination) if !Dir.exists?(destination)
|
192
|
+
|
193
|
+
# Clear out the indices before making them
|
194
|
+
Dir.entries(destination).each do |f|
|
195
|
+
index = File.join(destination, f)
|
196
|
+
File.delete(index) if File.file?(index)
|
197
|
+
end
|
198
|
+
|
199
|
+
temp_dir = File.join("templates")
|
200
|
+
template = Template.new(temp_dir, 'index.html', post_location=@config[:site][:posts])
|
201
|
+
indices = []
|
202
|
+
|
203
|
+
# Segment the posts into groups of 5
|
204
|
+
@posts.each_slice(5) { |posts|
|
205
|
+
indices << posts
|
206
|
+
}
|
207
|
+
|
208
|
+
# Create the indices and save them
|
209
|
+
indices.length.times { |i|
|
210
|
+
p_pg = nil
|
211
|
+
n_pg = nil
|
212
|
+
|
213
|
+
# Find the relative location (to the site) of the index
|
214
|
+
rel_index = File.join("/", @config[:site][:posts], @config[:site][:index])
|
215
|
+
|
216
|
+
# Figure out the previous/next pages, if they exist
|
217
|
+
p_pg = File.join(rel_index, i.to_s) if i > 0
|
218
|
+
n_pg = File.join(rel_index, (i+2).to_s) if i + 1 < indices.length
|
219
|
+
|
220
|
+
# Render the index page
|
221
|
+
indices[i] = template.render(indices[i], prev_page=p_pg, next_page=n_pg)
|
222
|
+
|
223
|
+
# Save the index page
|
224
|
+
index_file = File.join(destination, (i+1).to_s)
|
225
|
+
File.open(index_file, 'w') do |f|
|
226
|
+
f.print(indices[i])
|
227
|
+
end
|
228
|
+
}
|
229
|
+
end
|
230
|
+
|
231
|
+
|
232
|
+
# Publish the posts and pages
|
233
|
+
def push_content
|
234
|
+
temp_dir = File.join("templates")
|
235
|
+
|
236
|
+
# Create the post directory if it doesn't exist
|
237
|
+
destination = File.join(@config[:site][:root], @config[:site][:posts])
|
238
|
+
Dir.mkdir(destination) if !Dir.exists?(destination)
|
239
|
+
|
240
|
+
# Render and save each post to the post directory
|
241
|
+
template = Template.new(temp_dir, 'post.html')
|
242
|
+
@posts.each do |post|
|
243
|
+
post_file = File.join(destination, post[:id])
|
244
|
+
File.open(post_file, 'w') do |f|
|
245
|
+
f.print(template.render(post))
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
# Create the page directory if it doesn't exist
|
250
|
+
destination = File.join(@config[:site][:root], @config[:site][:pages])
|
251
|
+
Dir.mkdir(destination) if !Dir.exists?(destination)
|
252
|
+
|
253
|
+
# Render and save each page to the page directory
|
254
|
+
template = Template.new(temp_dir, 'page.html')
|
255
|
+
@pages.each do |page|
|
256
|
+
page_file = File.join(destination, page[:id])
|
257
|
+
File.open(page_file, 'w') do |f|
|
258
|
+
f.print(template.render(page))
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
end
|
263
|
+
|
264
|
+
# Move any new posts to the saved posts directory.
|
265
|
+
def gather_new_posts
|
266
|
+
new_dir = File.join("posts", "new")
|
267
|
+
|
268
|
+
Dir.entries(new_dir).each do |f|
|
269
|
+
post_file = File.join(new_dir, f)
|
270
|
+
if File.file?(post_file)
|
271
|
+
|
272
|
+
# Save the new post to the processed directory with metadata attached
|
273
|
+
File.open(post_file) do |new_post|
|
274
|
+
date = new_post.mtime
|
275
|
+
save_path = get_unused_filename(File.join("posts", date.strftime("%Y-%m-%d")), "post")
|
276
|
+
|
277
|
+
File.open(save_path, "w") do |save_file|
|
278
|
+
save_file.puts(@meta[:last_post] + 1)
|
279
|
+
save_file.puts(date.strftime("%Y-%m-%d %H:%M:%S %z"))
|
280
|
+
save_file.print(new_post.read)
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
# Remove the file from the new post directory
|
285
|
+
File.delete(post_file)
|
286
|
+
|
287
|
+
# Update the value of the last ID used
|
288
|
+
@meta[:last_post] += 1
|
289
|
+
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
# Process the pages and posts
|
295
|
+
def prepare_content
|
296
|
+
@posts = []
|
297
|
+
@pages = []
|
298
|
+
|
299
|
+
# Create a Post for each file in the posts directory
|
300
|
+
Dir.entries('posts').each do |f|
|
301
|
+
entry = File.join('posts', f)
|
302
|
+
if File.file?(entry)
|
303
|
+
@posts << Post.new(entry)
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
# Create a Page for each file in the pages directory
|
308
|
+
Dir.entries('pages').each do |f|
|
309
|
+
entry = File.join('pages', f)
|
310
|
+
if File.file?(entry)
|
311
|
+
@pages << Page.new(entry)
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
save_metadata
|
316
|
+
|
317
|
+
# Sort the posts by date, with most recent first
|
318
|
+
@posts.sort_by! { |post| post[:date] }
|
319
|
+
@posts.reverse!
|
320
|
+
end
|
321
|
+
|
322
|
+
end
|
metadata
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: den
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Peter Valdez
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-25 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description:
|
15
|
+
email: peter@someindividual.com
|
16
|
+
executables:
|
17
|
+
- den
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- bin/den
|
22
|
+
- lib/den/examples.rb
|
23
|
+
- lib/den/page.rb
|
24
|
+
- lib/den/post.rb
|
25
|
+
- lib/den/resource.rb
|
26
|
+
- lib/den/template.rb
|
27
|
+
- lib/den/utilities.rb
|
28
|
+
- lib/den.rb
|
29
|
+
- den.gemspec
|
30
|
+
homepage: https://github.com/azlyth/den
|
31
|
+
licenses: []
|
32
|
+
post_install_message:
|
33
|
+
rdoc_options: []
|
34
|
+
require_paths:
|
35
|
+
- lib
|
36
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
37
|
+
none: false
|
38
|
+
requirements:
|
39
|
+
- - ! '>='
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
43
|
+
none: false
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
requirements: []
|
49
|
+
rubyforge_project:
|
50
|
+
rubygems_version: 1.8.11
|
51
|
+
signing_key:
|
52
|
+
specification_version: 3
|
53
|
+
summary: A really simple static-site generator.
|
54
|
+
test_files: []
|