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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -1
  3. data/.travis.yml +5 -0
  4. data/README.md +130 -27
  5. data/lib/octopress.rb +8 -2
  6. data/lib/octopress/command.rb +3 -0
  7. data/lib/octopress/commands/build.rb +1 -4
  8. data/lib/octopress/commands/doctor.rb +3 -7
  9. data/lib/octopress/commands/helpers.rb +8 -3
  10. data/lib/octopress/commands/init.rb +15 -0
  11. data/lib/octopress/commands/new.rb +25 -22
  12. data/lib/octopress/commands/publish.rb +3 -1
  13. data/lib/octopress/commands/serve.rb +4 -7
  14. data/lib/octopress/configuration.rb +20 -12
  15. data/lib/octopress/draft.rb +39 -8
  16. data/lib/octopress/{core_ext.rb → ext/hash.rb} +0 -0
  17. data/lib/octopress/ext/titlecase.rb +37 -0
  18. data/lib/octopress/page.rb +49 -33
  19. data/lib/octopress/post.rb +17 -16
  20. data/lib/octopress/scaffold.rb +26 -0
  21. data/lib/octopress/version.rb +1 -1
  22. data/octopress.gemspec +1 -1
  23. data/scaffold/_octopress.yml +11 -0
  24. data/scaffold/_templates/page +6 -0
  25. data/scaffold/_templates/post +6 -0
  26. data/test/expected/_drafts/stupid-idea.markdown +6 -0
  27. data/test/expected/_layouts/page.html +1 -0
  28. data/test/expected/_layouts/post.html +1 -0
  29. data/test/expected/_octopress.yml +11 -0
  30. data/test/expected/_posts/2014-03-11-idea.markdown +6 -0
  31. data/test/expected/_posts/2014-03-12-awesome-stuff.markdown +6 -0
  32. data/test/expected/_posts/2014-03-13-awesome.markdown +6 -0
  33. data/test/expected/_site/2014/03/11/idea.html +1 -0
  34. data/test/expected/_site/2014/03/12/awesome-stuff.html +1 -0
  35. data/test/expected/_site/2014/03/13/awesome.html +1 -0
  36. data/test/expected/_site/awesome-page.html +1 -0
  37. data/test/expected/_site/cool-page.html +1 -0
  38. data/test/expected/_site/index.html +0 -0
  39. data/test/expected/_site/okay-page/index.html +1 -0
  40. data/test/expected/_templates/page +6 -0
  41. data/test/expected/_templates/post +6 -0
  42. data/test/expected/awesome-page.html +5 -0
  43. data/test/expected/cool-page.html +5 -0
  44. data/test/expected/index.html +0 -0
  45. data/test/expected/okay-page/index.html +5 -0
  46. data/test/test.rb +100 -0
  47. data/test/test_suite.rb +107 -0
  48. metadata +57 -10
  49. data/docs/_octopress.yml +0 -1
  50. data/docs/index.html +0 -1
  51. data/lib/octopress/commands/docs.rb +0 -74
@@ -2,10 +2,10 @@ module Octopress
2
2
  module Configuration
3
3
 
4
4
  DEFAULTS = {
5
- 'new_post_extension' => 'markdown',
6
- 'new_page_extension' => 'html',
7
- 'new_post_layout' => 'post',
8
- 'new_page_layout' => 'page',
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
- config = {}
16
+ user_config = {}
17
+
17
18
  if File.exist? file
18
- config = YAML.safe_load(File.open(file))
19
+ user_config = YAML.safe_load(File.open(file).read) || {}
19
20
  end
20
- @config = DEFAULTS.deep_merge(config)
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
- log_level = Jekyll.logger.log_level
27
- Jekyll.logger.log_level = Jekyll::Stevenson::WARN
28
- jekyll_config = Jekyll.configuration(options)
29
- Jekyll.logger.log_level = log_level
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 = jekyll_config
39
+ @jekyll_config = configs
32
40
  end
33
41
  end
34
42
  end
@@ -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
- def path
20
- name = "#{title_slug}.#{extension}"
21
- File.join(source, '_drafts', name)
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 = Pathname.new(file).read
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
@@ -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
@@ -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'] ||= 'page'
54
- @options['layout'] = @config['new_page_layout']
64
+ @options['type'] ||= 'page'
65
+ @options['layout'] = @config['page_layout']
55
66
  @options['date'] = convert_date @options['date']
56
- @options['extension'] ||= @config['new_page_extension']
57
- @options['template'] ||= @config['new_page_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
- begin
63
- Time.parse(date.to_s).iso8601
64
- rescue => error
65
- abort 'Could not parse date. Try formatting it like YYYY-MM-DD HH:MM'
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
- file = File.join(source, '_templates', file) if file
75
- if file
76
- abort "No template found at #{file}" unless File.exist? file
77
- parse_template Pathname.new(file).read
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
- Time.parse(@options['date']).strftime('%Y-%m-%d')
125
+ @options['date'].split('T')[0]
101
126
  end
102
127
 
103
- # Returns a string which is url compatible.
104
- #
105
- def title_slug
106
- value = @options['title'].gsub(/[^\x00-\x7F]/u, '')
107
- value.gsub!(/(&amp;|&)+/, 'and')
108
- value.gsub!(/[']+/, '')
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
- <<-TEMPLATE
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
@@ -2,12 +2,12 @@ module Octopress
2
2
  class Post < Page
3
3
 
4
4
  def set_default_options
5
- @options['type'] ||= 'post'
6
- @options['layout'] = @config['new_post_layout']
7
- @options['date'] = convert_date @options['date'] || Time.now
8
- @options['extension'] ||= @config['new_post_extension']
9
- @options['template'] ||= @config['new_post_template']
10
- raise "You must specify a title." if @options['title'].nil?
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
- # Post template defaults
18
+ # Returns a string which is url compatible.
19
19
  #
20
- def default_content
21
- <<-TEMPLATE
22
- ---
23
- layout: {{ layout }}
24
- title: {{ title }}
25
- date: {{ date }}
26
- categories: {{ categories }}
27
- ---
28
- TEMPLATE
20
+ def title_slug
21
+ value = (@options['slug'] || @options['title']).downcase
22
+ value.gsub!(/[^\x00-\x7F]/u, '')
23
+ value.gsub!(/(&amp;|&)+/, '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
@@ -1,3 +1,3 @@
1
1
  module Octopress
2
- VERSION = "3.0.0.alpha8"
2
+ VERSION = "3.0.0.rc.1"
3
3
  end
@@ -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.2"
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,11 @@
1
+ # Default extension for new posts and pages
2
+ post_ext: markdown
3
+ page_ext: html
4
+
5
+ # Default templates for posts and pages
6
+ # Found in _templates/
7
+ post_layout: post
8
+ page_layout: page
9
+
10
+ # Format titles with titlecase?
11
+ titlecase: true
@@ -0,0 +1,6 @@
1
+ ---
2
+ layout: {{ layout }}
3
+ title: {{ title }}
4
+ date: {{ date }}
5
+ ---
6
+
@@ -0,0 +1,6 @@
1
+ ---
2
+ layout: {{ layout }}
3
+ title: {{ title }}
4
+ date: {{ date }}
5
+ ---
6
+
@@ -0,0 +1,6 @@
1
+ ---
2
+ layout: post
3
+ title: "Stupid Idea"
4
+ date: 2014-03-10T15:20:00Z
5
+ ---
6
+
@@ -0,0 +1 @@
1
+ <div class='page'>{{ page.title }}{{ content }}</div>
@@ -0,0 +1 @@
1
+ <div class='post'>{{ page.title }}{{ content }}</div>