diary 0.1.5 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|