octopress 3.0.0.alpha8 → 3.0.0.rc.1
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 +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>
|