octopress 3.0.0.alpha8 → 3.0.0.rc.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -1
- data/.travis.yml +5 -0
- data/README.md +130 -27
- data/lib/octopress.rb +8 -2
- data/lib/octopress/command.rb +3 -0
- data/lib/octopress/commands/build.rb +1 -4
- data/lib/octopress/commands/doctor.rb +3 -7
- data/lib/octopress/commands/helpers.rb +8 -3
- data/lib/octopress/commands/init.rb +15 -0
- data/lib/octopress/commands/new.rb +25 -22
- data/lib/octopress/commands/publish.rb +3 -1
- data/lib/octopress/commands/serve.rb +4 -7
- data/lib/octopress/configuration.rb +20 -12
- data/lib/octopress/draft.rb +39 -8
- data/lib/octopress/{core_ext.rb → ext/hash.rb} +0 -0
- data/lib/octopress/ext/titlecase.rb +37 -0
- data/lib/octopress/page.rb +49 -33
- data/lib/octopress/post.rb +17 -16
- data/lib/octopress/scaffold.rb +26 -0
- data/lib/octopress/version.rb +1 -1
- data/octopress.gemspec +1 -1
- data/scaffold/_octopress.yml +11 -0
- data/scaffold/_templates/page +6 -0
- data/scaffold/_templates/post +6 -0
- data/test/expected/_drafts/stupid-idea.markdown +6 -0
- data/test/expected/_layouts/page.html +1 -0
- data/test/expected/_layouts/post.html +1 -0
- data/test/expected/_octopress.yml +11 -0
- data/test/expected/_posts/2014-03-11-idea.markdown +6 -0
- data/test/expected/_posts/2014-03-12-awesome-stuff.markdown +6 -0
- data/test/expected/_posts/2014-03-13-awesome.markdown +6 -0
- data/test/expected/_site/2014/03/11/idea.html +1 -0
- data/test/expected/_site/2014/03/12/awesome-stuff.html +1 -0
- data/test/expected/_site/2014/03/13/awesome.html +1 -0
- data/test/expected/_site/awesome-page.html +1 -0
- data/test/expected/_site/cool-page.html +1 -0
- data/test/expected/_site/index.html +0 -0
- data/test/expected/_site/okay-page/index.html +1 -0
- data/test/expected/_templates/page +6 -0
- data/test/expected/_templates/post +6 -0
- data/test/expected/awesome-page.html +5 -0
- data/test/expected/cool-page.html +5 -0
- data/test/expected/index.html +0 -0
- data/test/expected/okay-page/index.html +5 -0
- data/test/test.rb +100 -0
- data/test/test_suite.rb +107 -0
- metadata +57 -10
- data/docs/_octopress.yml +0 -1
- data/docs/index.html +0 -1
- data/lib/octopress/commands/docs.rb +0 -74
@@ -2,10 +2,10 @@ module Octopress
|
|
2
2
|
module Configuration
|
3
3
|
|
4
4
|
DEFAULTS = {
|
5
|
-
'
|
6
|
-
'
|
7
|
-
'
|
8
|
-
'
|
5
|
+
'post_ext' => 'markdown',
|
6
|
+
'page_ext' => 'html',
|
7
|
+
'post_layout' => 'post',
|
8
|
+
'page_layout' => 'page',
|
9
9
|
'titlecase' => true
|
10
10
|
}
|
11
11
|
|
@@ -13,22 +13,30 @@ module Octopress
|
|
13
13
|
return @config if @config
|
14
14
|
|
15
15
|
file = options['octopress-config'] || '_octopress.yml'
|
16
|
-
|
16
|
+
user_config = {}
|
17
|
+
|
17
18
|
if File.exist? file
|
18
|
-
|
19
|
+
user_config = YAML.safe_load(File.open(file).read) || {}
|
19
20
|
end
|
20
|
-
|
21
|
+
|
22
|
+
user_config = user_config.deep_merge(options['override'] || {})
|
23
|
+
user_config = (options['defaults'] || {}).deep_merge(user_config)
|
24
|
+
|
25
|
+
@config = DEFAULTS.deep_merge(user_config)
|
21
26
|
end
|
22
27
|
|
23
28
|
def self.jekyll_config(options={})
|
24
29
|
return @jekyll_config if @jekyll_config
|
25
30
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
31
|
+
configs = Jekyll::Configuration::DEFAULTS
|
32
|
+
|
33
|
+
(options['config'] || ['_config.yml']).each do |file|
|
34
|
+
if File.exist? file
|
35
|
+
configs = configs.deep_merge YAML.safe_load(File.open(file))
|
36
|
+
end
|
37
|
+
end
|
30
38
|
|
31
|
-
@jekyll_config =
|
39
|
+
@jekyll_config = configs
|
32
40
|
end
|
33
41
|
end
|
34
42
|
end
|
data/lib/octopress/draft.rb
CHANGED
@@ -1,40 +1,71 @@
|
|
1
1
|
module Octopress
|
2
2
|
class Draft < Post
|
3
3
|
|
4
|
+
def set_default_options
|
5
|
+
super
|
6
|
+
@options['type'] = 'draft'
|
7
|
+
end
|
8
|
+
|
9
|
+
def path
|
10
|
+
name = "#{title_slug}.#{extension}"
|
11
|
+
File.join(source, '_drafts', name)
|
12
|
+
end
|
13
|
+
|
14
|
+
# -----
|
15
|
+
# Methods for publishing drafts
|
16
|
+
# -----
|
17
|
+
|
18
|
+
# Create a new post from draft file
|
19
|
+
#
|
20
|
+
# Sets post options based on draft file contents
|
21
|
+
# and options passed to the publish command
|
22
|
+
#
|
4
23
|
def publish
|
24
|
+
|
5
25
|
post_options = {
|
6
26
|
'title' => read_draft_title,
|
27
|
+
'slug' => publish_slug,
|
28
|
+
'date' => @options['date'],
|
7
29
|
'content' => read_draft_content,
|
8
30
|
'type' => 'post from draft'
|
9
31
|
}
|
32
|
+
|
33
|
+
# Create a new post file
|
34
|
+
#
|
10
35
|
Post.new(post_options).write
|
36
|
+
|
37
|
+
# Remove the old draft file
|
38
|
+
#
|
11
39
|
FileUtils.rm @options['path']
|
12
|
-
end
|
13
40
|
|
14
|
-
def set_default_options
|
15
|
-
super
|
16
|
-
@options['type'] = 'draft'
|
17
41
|
end
|
18
42
|
|
19
|
-
|
20
|
-
|
21
|
-
|
43
|
+
# Get the slug from options or filename
|
44
|
+
#
|
45
|
+
def publish_slug
|
46
|
+
@options['slug'] || File.basename(@options['path'], '.*')
|
22
47
|
end
|
23
48
|
|
49
|
+
# Reads the file from _drafts/[path]
|
50
|
+
#
|
24
51
|
def read
|
25
52
|
if @draft_content
|
26
53
|
@draft_content
|
27
54
|
else
|
28
55
|
file = @options['path']
|
29
56
|
abort "File #{file} not found." if !File.exist? file
|
30
|
-
@draft_content =
|
57
|
+
@draft_content = File.open(file).read
|
31
58
|
end
|
32
59
|
end
|
33
60
|
|
61
|
+
# Get title from draft post file
|
62
|
+
#
|
34
63
|
def read_draft_title
|
35
64
|
read.match(/title:\s+(.+)?$/)[1]
|
36
65
|
end
|
37
66
|
|
67
|
+
# Get content from draft post file
|
68
|
+
#
|
38
69
|
def read_draft_content
|
39
70
|
read.sub(/date:\s+.+?$/, "date: #{@options['date']}")
|
40
71
|
end
|
File without changes
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class String
|
2
|
+
def titlecase
|
3
|
+
small_words = %w(a an and as at but by en for if in of on or the to v v. via vs vs.)
|
4
|
+
|
5
|
+
x = split(" ").map do |word|
|
6
|
+
# note: word could contain non-word characters!
|
7
|
+
# downcase all small_words, capitalize the rest
|
8
|
+
small_words.include?(word.gsub(/\W/, "").downcase) ? word.downcase! : word.smart_capitalize!
|
9
|
+
word
|
10
|
+
end
|
11
|
+
# capitalize first and last words
|
12
|
+
x.first.to_s.smart_capitalize!
|
13
|
+
x.last.to_s.smart_capitalize!
|
14
|
+
# small words are capitalized after colon, period, exclamation mark, question mark
|
15
|
+
x.join(" ").gsub(/(:|\.|!|\?)\s?(\W*#{small_words.join("|")}\W*)\s/) { "#{$1} #{$2.smart_capitalize} " }
|
16
|
+
end
|
17
|
+
|
18
|
+
def titlecase!
|
19
|
+
replace(titlecase)
|
20
|
+
end
|
21
|
+
|
22
|
+
def smart_capitalize
|
23
|
+
target = dup
|
24
|
+
# ignore any leading crazy characters and capitalize the first real character
|
25
|
+
if target =~ /^['"\(\[']*([a-z])/
|
26
|
+
i = index($1)
|
27
|
+
x = target[i,target.length]
|
28
|
+
# word with capitals and periods mid-word are left alone
|
29
|
+
target[i,1] = target[i,1].upcase unless x =~ /[A-Z]/ or x =~ /\.\w+/
|
30
|
+
end
|
31
|
+
target
|
32
|
+
end
|
33
|
+
|
34
|
+
def smart_capitalize!
|
35
|
+
replace(smart_capitalize)
|
36
|
+
end
|
37
|
+
end
|
data/lib/octopress/page.rb
CHANGED
@@ -5,6 +5,15 @@ module Octopress
|
|
5
5
|
@config = Octopress.config(options)
|
6
6
|
@options = options
|
7
7
|
set_default_options
|
8
|
+
|
9
|
+
# Ensure title
|
10
|
+
#
|
11
|
+
@options['title'] ||= ''
|
12
|
+
|
13
|
+
# Ensure a quoted title
|
14
|
+
#
|
15
|
+
@options['title'] = "\"#{@options['title']}\""
|
16
|
+
|
8
17
|
@content = options['content'] || content
|
9
18
|
end
|
10
19
|
|
@@ -37,9 +46,11 @@ module Octopress
|
|
37
46
|
raise "You must specify a path." unless file
|
38
47
|
|
39
48
|
# If path ends with a slash, make it an index
|
49
|
+
#
|
40
50
|
file += "index" if file =~ /\/$/
|
41
51
|
|
42
52
|
# if path has no extension, add the default extension
|
53
|
+
#
|
43
54
|
file += ".#{extension}" unless file =~ /\.\w+$/
|
44
55
|
|
45
56
|
@path = File.join(source, file)
|
@@ -50,31 +61,44 @@ module Octopress
|
|
50
61
|
end
|
51
62
|
|
52
63
|
def set_default_options
|
53
|
-
@options['type']
|
54
|
-
@options['layout'] = @config['
|
64
|
+
@options['type'] ||= 'page'
|
65
|
+
@options['layout'] = @config['page_layout']
|
55
66
|
@options['date'] = convert_date @options['date']
|
56
|
-
@options['extension'] ||= @config['
|
57
|
-
@options['template']
|
67
|
+
@options['extension'] ||= @config['page_ext']
|
68
|
+
@options['template'] ||= @config['page_template']
|
58
69
|
end
|
59
70
|
|
60
71
|
def convert_date(date)
|
61
72
|
if date
|
62
|
-
|
63
|
-
Time.
|
64
|
-
|
65
|
-
|
73
|
+
if @options['date'] == 'now'
|
74
|
+
@options['date'] = Time.now.iso8601
|
75
|
+
else
|
76
|
+
begin
|
77
|
+
Time.parse(date.to_s).iso8601
|
78
|
+
rescue => error
|
79
|
+
puts 'Could not parse date. Try formatting it like YYYY-MM-DD HH:MM'
|
80
|
+
abort error.message
|
81
|
+
end
|
66
82
|
end
|
67
83
|
end
|
68
84
|
end
|
69
85
|
|
70
|
-
# Load the user provide or default template for a new post.
|
86
|
+
# Load the user provide or default template for a new post or page.
|
71
87
|
#
|
72
88
|
def content
|
89
|
+
|
90
|
+
# Handle case where user passes the full path
|
91
|
+
#
|
73
92
|
file = @options['template']
|
74
|
-
|
75
|
-
if file
|
76
|
-
|
77
|
-
|
93
|
+
|
94
|
+
if file
|
95
|
+
file.sub(/^_templates\//, '')
|
96
|
+
file = File.join(source, '_templates', file) if file
|
97
|
+
if File.exist? file
|
98
|
+
parse_template File.open(file).read
|
99
|
+
else
|
100
|
+
abort "No #{@options['type']} template found at #{file}"
|
101
|
+
end
|
78
102
|
else
|
79
103
|
parse_template default_content
|
80
104
|
end
|
@@ -83,45 +107,37 @@ module Octopress
|
|
83
107
|
# Render Liquid vars in YAML front-matter.
|
84
108
|
def parse_template(input)
|
85
109
|
|
110
|
+
@options['title'].titlecase! if @config['titlecase']
|
86
111
|
# If possible only parse the YAML front matter.
|
87
112
|
# If YAML front-matter dashes aren't present parse the whole
|
88
113
|
# template and add dashes.
|
89
114
|
#
|
90
115
|
parsed = if input =~ /\A-{3}\s+(.+?)\s+-{3}\s+(.+)/m
|
91
116
|
template = Liquid::Template.parse($1)
|
92
|
-
"---\n#{template.render(@options)}\n---\n\n#{$2}"
|
117
|
+
"---\n#{template.render(@options).strip}\n---\n\n#{$2}"
|
93
118
|
else
|
94
119
|
template = Liquid::Template.parse(input)
|
95
|
-
"---\n#{template.render(@options)}\n---\n\n"
|
120
|
+
"---\n#{template.render(@options).strip}\n---\n\n"
|
96
121
|
end
|
97
122
|
end
|
98
123
|
|
99
124
|
def date_slug
|
100
|
-
|
125
|
+
@options['date'].split('T')[0]
|
101
126
|
end
|
102
127
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
value.gsub!(/\W+/, ' ')
|
110
|
-
value.strip!
|
111
|
-
value.downcase!
|
112
|
-
value.gsub!(' ', '-')
|
113
|
-
value
|
128
|
+
def front_matter(vars)
|
129
|
+
fm = []
|
130
|
+
vars.each do |v|
|
131
|
+
fm << "#{v}: {{ #{v} }}" if @options[v]
|
132
|
+
end
|
133
|
+
fm.join("\n")
|
114
134
|
end
|
115
135
|
|
116
136
|
# Page template defaults
|
117
137
|
#
|
118
138
|
def default_content
|
119
|
-
|
120
|
-
---
|
121
|
-
layout: {{ layout }}
|
122
|
-
title: {{ title }}
|
123
|
-
---
|
124
|
-
TEMPLATE
|
139
|
+
front_matter %w{layout title date}
|
125
140
|
end
|
141
|
+
|
126
142
|
end
|
127
143
|
end
|
data/lib/octopress/post.rb
CHANGED
@@ -2,12 +2,12 @@ module Octopress
|
|
2
2
|
class Post < Page
|
3
3
|
|
4
4
|
def set_default_options
|
5
|
-
@options['type']
|
6
|
-
@options['layout']
|
7
|
-
@options['date']
|
8
|
-
@options['
|
9
|
-
@options['
|
10
|
-
|
5
|
+
@options['type'] ||= 'post'
|
6
|
+
@options['layout'] = @config['post_layout']
|
7
|
+
@options['date'] ||= Time.now.iso8601
|
8
|
+
@options['date'] = convert_date @options['date']
|
9
|
+
@options['extension'] ||= @config['post_ext']
|
10
|
+
@options['template'] ||= @config['post_template']
|
11
11
|
end
|
12
12
|
|
13
13
|
def path
|
@@ -15,17 +15,18 @@ module Octopress
|
|
15
15
|
File.join(source, '_posts', name)
|
16
16
|
end
|
17
17
|
|
18
|
-
#
|
18
|
+
# Returns a string which is url compatible.
|
19
19
|
#
|
20
|
-
def
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
20
|
+
def title_slug
|
21
|
+
value = (@options['slug'] || @options['title']).downcase
|
22
|
+
value.gsub!(/[^\x00-\x7F]/u, '')
|
23
|
+
value.gsub!(/(&|&)+/, 'and')
|
24
|
+
value.gsub!(/[']+/, '')
|
25
|
+
value.gsub!(/\W+/, ' ')
|
26
|
+
value.strip!
|
27
|
+
value.gsub!(' ', '-')
|
28
|
+
value
|
29
29
|
end
|
30
|
+
|
30
31
|
end
|
31
32
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Octopress
|
2
|
+
class Scaffold
|
3
|
+
attr_reader :path, :force
|
4
|
+
|
5
|
+
def initialize(args, options)
|
6
|
+
@path = File.expand_path(args.join(" "), Dir.pwd)
|
7
|
+
@force = !!options['force']
|
8
|
+
end
|
9
|
+
|
10
|
+
def write
|
11
|
+
if !force && (File.exist?(path + '/_templates') ||
|
12
|
+
File.exist?(path + '/_octopress.yml'))
|
13
|
+
abort "Some files already exist. Use --force to overwrite."
|
14
|
+
end
|
15
|
+
|
16
|
+
FileUtils.cp_r scaffold_path + '/.', path
|
17
|
+
|
18
|
+
puts "Octopress scaffold added to #{path}."
|
19
|
+
end
|
20
|
+
|
21
|
+
def scaffold_path
|
22
|
+
Octopress.expand_gem_path('scaffold')
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
data/lib/octopress/version.rb
CHANGED
data/octopress.gemspec
CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
21
|
spec.add_runtime_dependency "mercenary", "~> 0.3.1"
|
22
|
-
spec.add_runtime_dependency "jekyll", "~> 1.4.
|
22
|
+
spec.add_runtime_dependency "jekyll", "~> 1.4.3"
|
23
23
|
|
24
24
|
spec.add_development_dependency "bundler", "~> 1.3"
|
25
25
|
spec.add_development_dependency "pry-debugger"
|
@@ -0,0 +1 @@
|
|
1
|
+
<div class='page'>{{ page.title }}{{ content }}</div>
|
@@ -0,0 +1 @@
|
|
1
|
+
<div class='post'>{{ page.title }}{{ content }}</div>
|