diary 0.1.5 → 0.2.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.
- data/.gitignore +3 -22
- data/Gemfile +4 -0
- data/Gemfile.lock +28 -0
- data/Rakefile +2 -20
- data/bin/diary +1 -40
- data/diary.gemspec +19 -60
- data/lib/diary.rb +23 -20
- data/lib/diary/cli.rb +5 -43
- data/lib/diary/cli/commands.rb +23 -0
- data/lib/diary/cli/commands/compile.rb +16 -0
- data/lib/diary/cli/commands/init.rb +40 -0
- data/lib/diary/cli/commands/new_item.rb +9 -0
- data/lib/diary/cli/commands/server.rb +13 -0
- data/lib/diary/cli/commands/sync.rb +20 -0
- data/lib/diary/cli/parser.rb +37 -0
- data/lib/diary/item/base.rb +26 -0
- data/lib/diary/item/creator.rb +80 -0
- data/lib/diary/item/data.rb +37 -0
- data/lib/diary/item/finder.rb +37 -0
- data/lib/diary/item/output.rb +58 -0
- data/lib/diary/item/snippet.rb +9 -0
- data/lib/diary/item/template.rb +38 -0
- data/lib/diary/item/url.rb +9 -0
- data/lib/diary/items/page.rb +7 -0
- data/lib/diary/items/post.rb +10 -0
- data/lib/diary/message.rb +40 -19
- data/lib/diary/server.rb +5 -0
- data/lib/diary/snippet.rb +19 -0
- data/lib/diary/version.rb +3 -0
- metadata +85 -38
- data/LICENSE +0 -20
- data/README.rdoc +0 -3
- data/VERSION +0 -1
- data/lib/diary/draft.rb +0 -14
- data/lib/diary/item.rb +0 -138
- data/lib/diary/output.rb +0 -57
- data/lib/diary/page.rb +0 -6
- data/lib/diary/post.rb +0 -22
- data/lib/diary/site.rb +0 -55
- data/lib/diary/template.rb +0 -27
- data/test/helper.rb +0 -10
- data/test/test_diary.rb +0 -7
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module Diary
|
4
|
+
module CLI
|
5
|
+
module Parser
|
6
|
+
def parse(args)
|
7
|
+
options = OpenStruct.new
|
8
|
+
options.force = false
|
9
|
+
|
10
|
+
opts = OptionParser.new do |opts|
|
11
|
+
opts.banner = "Usage: diary ACTION [-vf]"
|
12
|
+
|
13
|
+
opts.separator "\nSpecific options:"
|
14
|
+
|
15
|
+
opts.on("-f", "--[no-]force", "Force all items to compile") do |f|
|
16
|
+
options.force = f
|
17
|
+
end
|
18
|
+
|
19
|
+
opts.separator "\nCommon options:"
|
20
|
+
|
21
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
22
|
+
$stdout.puts opts
|
23
|
+
exit
|
24
|
+
end
|
25
|
+
|
26
|
+
opts.on_tail("-v", "--version", "Show version") do
|
27
|
+
$stdout.puts "diary #{VERSION}"
|
28
|
+
exit
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
opts.parse!(args)
|
33
|
+
options
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Diary
|
2
|
+
module Item
|
3
|
+
class Base
|
4
|
+
attr_reader :path
|
5
|
+
|
6
|
+
def initialize(path)
|
7
|
+
@path = path
|
8
|
+
end
|
9
|
+
|
10
|
+
def basename
|
11
|
+
File.basename(path, '.md')
|
12
|
+
end
|
13
|
+
|
14
|
+
def classname
|
15
|
+
self.class.name.downcase
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.base_directory
|
19
|
+
self.name.downcase.pluralize
|
20
|
+
end
|
21
|
+
|
22
|
+
extend Creator
|
23
|
+
extend Finder
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
module Diary
|
3
|
+
module Item
|
4
|
+
module Creator
|
5
|
+
def self.extended(base)
|
6
|
+
base.send :include, Peristance
|
7
|
+
end
|
8
|
+
|
9
|
+
module Peristance
|
10
|
+
def save!(title = nil)
|
11
|
+
unless persisted?
|
12
|
+
self.class.create(title || basename)
|
13
|
+
else
|
14
|
+
self
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def persisted?
|
19
|
+
File.exists?(path)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
ACCENTS = {
|
24
|
+
['á','à','â','ä','ã'] => 'a',
|
25
|
+
['Ã','Ä','Â','À','�?'] => 'A',
|
26
|
+
['é','è','ê','ë'] => 'e',
|
27
|
+
['Ë','É','È','Ê'] => 'E',
|
28
|
+
['í','ì','î','ï'] => 'i',
|
29
|
+
['�?','Î','Ì','�?'] => 'I',
|
30
|
+
['ó','ò','ô','ö','õ'] => 'o',
|
31
|
+
['Õ','Ö','Ô','Ò','Ó'] => 'O',
|
32
|
+
['ú','ù','û','ü'] => 'u',
|
33
|
+
['Ú','Û','Ù','Ü'] => 'U',
|
34
|
+
['ç'] => 'c', ['Ç'] => 'C',
|
35
|
+
['ñ'] => 'n', ['Ñ'] => 'N'
|
36
|
+
}
|
37
|
+
|
38
|
+
def create(title)
|
39
|
+
slug = slugify(title)
|
40
|
+
path = resolve_path(slug)
|
41
|
+
|
42
|
+
ensure_directories_exists!(path)
|
43
|
+
|
44
|
+
unless File.exists?(path)
|
45
|
+
File.open(path, "w+") do |f|
|
46
|
+
f.puts "---\n"
|
47
|
+
f.puts "title: #{title}"
|
48
|
+
f.puts "\n---\n"
|
49
|
+
end
|
50
|
+
|
51
|
+
Diary.message :create, path, :green
|
52
|
+
else
|
53
|
+
Diary.message :exist, path, :yellow
|
54
|
+
end
|
55
|
+
|
56
|
+
self.new(path)
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def slugify(str)
|
62
|
+
ACCENTS.each do |ac,rep|
|
63
|
+
ac.each do |s|
|
64
|
+
str = str.gsub(s, rep)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
str.gsub(/[ ]+/, " ").gsub(/ /, "-").downcase
|
69
|
+
end
|
70
|
+
|
71
|
+
def resolve_path(slug)
|
72
|
+
File.join(base_directory, "#{slug}.md")
|
73
|
+
end
|
74
|
+
|
75
|
+
def ensure_directories_exists!(path)
|
76
|
+
FileUtils.mkpath File.dirname(path)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Diary
|
2
|
+
module Item
|
3
|
+
module Data
|
4
|
+
attr_reader :data
|
5
|
+
|
6
|
+
def initialize(*args)
|
7
|
+
super
|
8
|
+
load_data
|
9
|
+
end
|
10
|
+
|
11
|
+
def reload_data
|
12
|
+
@data = load_data
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def load_data
|
18
|
+
if File.exists?(path)
|
19
|
+
@data ||= OpenStruct.new(YAML.load_file(path)).freeze
|
20
|
+
create_attr_readers_from_data_table!
|
21
|
+
|
22
|
+
@data
|
23
|
+
else
|
24
|
+
nil
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def create_attr_readers_from_data_table!
|
29
|
+
data.instance_variable_get(:@table).tap do |h|
|
30
|
+
h.each_key do |k|
|
31
|
+
self.class.send(:define_method, k) { data.send k } unless self.class.method_defined?(k)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Diary
|
2
|
+
module Item
|
3
|
+
module Finder
|
4
|
+
def find(r)
|
5
|
+
file_list.each do |p|
|
6
|
+
return initialize_item(p) if p.match(r)
|
7
|
+
end
|
8
|
+
|
9
|
+
nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def all
|
13
|
+
file_list.map do |p|
|
14
|
+
initialize_item(p)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def first
|
19
|
+
all.first
|
20
|
+
end
|
21
|
+
|
22
|
+
def last
|
23
|
+
all.last
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def file_list
|
29
|
+
Dir[File.join(base_directory, "**", "*.md")]
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize_item(p)
|
33
|
+
self.new(p)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Diary
|
2
|
+
module Item
|
3
|
+
module Output
|
4
|
+
def output(force = false)
|
5
|
+
if changed? or force
|
6
|
+
FileUtils.mkpath output_directory
|
7
|
+
File.open(output_path, 'w+') { |f| f.puts render }
|
8
|
+
Diary.message (force ? :force : :update), output_path, (force ? :yellow : :green)
|
9
|
+
|
10
|
+
return true
|
11
|
+
else
|
12
|
+
Diary.message :identical, output_path, :yellow
|
13
|
+
|
14
|
+
return false
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def content
|
19
|
+
return @content if @content
|
20
|
+
|
21
|
+
File.open(path, 'r') do |f|
|
22
|
+
@content ||= BlueCloth.new(f.read.split(/---\n/).slice(-1).strip).to_html
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def render
|
29
|
+
File.open(template, 'r') do |t|
|
30
|
+
ERB.new(t.read).result(binding)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def changed?
|
35
|
+
file = File.open(path, 'r') if File.exists?(path)
|
36
|
+
output_file = File.open(output_path, 'r') if File.exists?(output_path)
|
37
|
+
|
38
|
+
if file and output_file
|
39
|
+
result = file.mtime > output_file.ctime
|
40
|
+
else
|
41
|
+
result = true
|
42
|
+
end
|
43
|
+
|
44
|
+
[file, output_file].each { |f| f.close if f and f.is_a?(File) }
|
45
|
+
|
46
|
+
result
|
47
|
+
end
|
48
|
+
|
49
|
+
def output_path(directory = "public")
|
50
|
+
path.gsub(self.class.base_directory, directory).gsub('.md', (path.match("index.md") ? '.html' : '/index.html'))
|
51
|
+
end
|
52
|
+
|
53
|
+
def output_directory
|
54
|
+
File.dirname(output_path)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Diary
|
2
|
+
module Item
|
3
|
+
module Template
|
4
|
+
# This method will go down the template lookup procedure and will
|
5
|
+
# return the first file path to match an existing file.
|
6
|
+
#
|
7
|
+
# The lookup order is as follow:
|
8
|
+
#
|
9
|
+
# 1 The template name supplied in the data section
|
10
|
+
# 2 A template with the same basename
|
11
|
+
# 3 A template with the name of the item class (Page, Post, etc…)
|
12
|
+
# 4 The index template file
|
13
|
+
def template
|
14
|
+
Diary.message :invoke, template_lookup, :cyan
|
15
|
+
|
16
|
+
template_lookup
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def template_lookup
|
22
|
+
template_names.each do |name|
|
23
|
+
return template_path(name) if File.exists?(template_path(name))
|
24
|
+
end
|
25
|
+
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def template_names
|
30
|
+
[(defined?(Data) ? data.template : nil), basename, classname, 'index'].compact
|
31
|
+
end
|
32
|
+
|
33
|
+
def template_path(name)
|
34
|
+
File.join("templates", "#{name}.html.erb")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/diary/message.rb
CHANGED
@@ -1,23 +1,44 @@
|
|
1
1
|
module Diary
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
#
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
def
|
20
|
-
|
2
|
+
class Message
|
3
|
+
DEFAULT_PADDING = 12
|
4
|
+
|
5
|
+
# Embed in a String to clear all previous ANSI sequences.
|
6
|
+
CLEAR = "\e[0m"
|
7
|
+
# Embed in a String to add bold
|
8
|
+
BOLD = "\e[1m"
|
9
|
+
# Embed in a String to add color
|
10
|
+
BLACK = "\e[30m"
|
11
|
+
RED = "\e[31m"
|
12
|
+
GREEN = "\e[32m"
|
13
|
+
YELLOW = "\e[33m"
|
14
|
+
BLUE = "\e[34m"
|
15
|
+
MAGENTA = "\e[35m"
|
16
|
+
CYAN = "\e[36m"
|
17
|
+
WHITE = "\e[37m"
|
18
|
+
|
19
|
+
def initialize(keyword, message, color = false)
|
20
|
+
keyword = add_padding(keyword.to_s)
|
21
|
+
keyword = set_color(keyword, color) if color
|
22
|
+
|
23
|
+
$stdout.puts "#{keyword} #{message}"
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def add_padding(str, padding = DEFAULT_PADDING)
|
29
|
+
spaces = " " * [0, (padding - str.size)].max
|
30
|
+
spaces + str
|
31
|
+
end
|
32
|
+
|
33
|
+
def set_color(str, color)
|
34
|
+
color = self.class.const_get(color.to_s.upcase)
|
35
|
+
color + str + CLEAR
|
36
|
+
end
|
37
|
+
|
38
|
+
module Shorthand
|
39
|
+
def message(*args)
|
40
|
+
::Diary::Message.new(*args)
|
41
|
+
end
|
21
42
|
end
|
22
43
|
end
|
23
44
|
end
|
data/lib/diary/server.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module Diary
|
2
|
+
class Snippet
|
3
|
+
attr_reader :path
|
4
|
+
|
5
|
+
def initialize(name)
|
6
|
+
@path = File.join("snippets", "#{name}.html")
|
7
|
+
end
|
8
|
+
|
9
|
+
def content
|
10
|
+
unless @content
|
11
|
+
File.open(path, 'r') do |file|
|
12
|
+
@content ||= file.read
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
@content
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|