monad 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (188) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTING.markdown +91 -0
  3. data/Gemfile +1 -1
  4. data/History.markdown +772 -0
  5. data/{README.md → README.markdown} +5 -2
  6. data/Rakefile +163 -1
  7. data/bin/monad +86 -30
  8. data/features/create_sites.feature +54 -25
  9. data/features/data.feature +65 -0
  10. data/features/data_sources.feature +10 -10
  11. data/features/drafts.feature +5 -5
  12. data/features/embed_filters.feature +10 -10
  13. data/features/include_tag.feature +48 -0
  14. data/features/markdown.feature +5 -5
  15. data/features/pagination.feature +38 -10
  16. data/features/permalinks.feature +31 -11
  17. data/features/post_data.feature +41 -41
  18. data/features/post_excerpts.feature +50 -0
  19. data/features/site_configuration.feature +47 -26
  20. data/features/site_data.feature +30 -24
  21. data/features/step_definitions/{monad_steps.rb → jekyll_steps.rb} +66 -52
  22. data/features/support/env.rb +27 -8
  23. data/lib/jekyll.rb +99 -0
  24. data/lib/jekyll/cleaner.rb +73 -0
  25. data/lib/{monad → jekyll}/command.rb +6 -6
  26. data/lib/{monad → jekyll}/commands/build.rb +9 -9
  27. data/lib/jekyll/commands/doctor.rb +67 -0
  28. data/lib/jekyll/commands/new.rb +67 -0
  29. data/lib/jekyll/commands/serve.rb +65 -0
  30. data/lib/{monad → jekyll}/configuration.rb +60 -18
  31. data/lib/{monad → jekyll}/converter.rb +1 -1
  32. data/lib/{monad → jekyll}/converters/identity.rb +1 -1
  33. data/lib/{monad → jekyll}/converters/markdown.rb +2 -2
  34. data/lib/jekyll/converters/markdown/kramdown_parser.rb +29 -0
  35. data/lib/{monad → jekyll}/converters/markdown/maruku_parser.rb +12 -8
  36. data/lib/{monad → jekyll}/converters/markdown/rdiscount_parser.rb +4 -2
  37. data/lib/{monad → jekyll}/converters/markdown/redcarpet_parser.rb +1 -1
  38. data/lib/{monad → jekyll}/converters/textile.rb +1 -1
  39. data/lib/{monad → jekyll}/convertible.rb +39 -17
  40. data/lib/{monad → jekyll}/core_ext.rb +22 -4
  41. data/lib/jekyll/deprecator.rb +36 -0
  42. data/lib/{monad → jekyll}/draft.rb +1 -1
  43. data/lib/{monad → jekyll}/drivers/json_driver.rb +1 -1
  44. data/lib/{monad → jekyll}/drivers/yaml_driver.rb +1 -1
  45. data/lib/{monad → jekyll}/errors.rb +1 -1
  46. data/lib/jekyll/excerpt.rb +113 -0
  47. data/lib/{monad → jekyll}/filters.rb +16 -6
  48. data/lib/{monad → jekyll}/generator.rb +1 -1
  49. data/lib/jekyll/generators/pagination.rb +214 -0
  50. data/lib/{monad → jekyll}/layout.rb +4 -1
  51. data/lib/{monad → jekyll}/mime.types +0 -0
  52. data/lib/{monad → jekyll}/page.rb +36 -39
  53. data/lib/{monad → jekyll}/plugin.rb +1 -1
  54. data/lib/{monad → jekyll}/post.rb +58 -123
  55. data/lib/jekyll/related_posts.rb +59 -0
  56. data/lib/{monad → jekyll}/site.rb +120 -123
  57. data/lib/{monad → jekyll}/static_file.rb +1 -1
  58. data/lib/jekyll/stevenson.rb +89 -0
  59. data/lib/jekyll/tags/gist.rb +48 -0
  60. data/lib/{monad → jekyll}/tags/highlight.rb +3 -3
  61. data/lib/jekyll/tags/include.rb +135 -0
  62. data/lib/{monad → jekyll}/tags/post_url.rb +8 -6
  63. data/lib/jekyll/url.rb +67 -0
  64. data/lib/monad.rb +36 -27
  65. data/lib/site_template/_config.yml +2 -1
  66. data/lib/site_template/_layouts/default.html +21 -23
  67. data/lib/site_template/_layouts/post.html +1 -1
  68. data/lib/site_template/_posts/{0000-00-00-welcome-to-monad.markdown.erb → 0000-00-00-welcome-to-jekyll.markdown.erb} +6 -6
  69. data/lib/site_template/css/main.css +22 -27
  70. data/lib/site_template/index.html +2 -2
  71. data/monad.gemspec +153 -52
  72. data/site/.gitignore +4 -0
  73. data/site/CNAME +1 -0
  74. data/site/README +1 -0
  75. data/site/_config.yml +6 -0
  76. data/site/_includes/analytics.html +32 -0
  77. data/site/_includes/docs_contents.html +16 -0
  78. data/site/_includes/docs_contents_mobile.html +23 -0
  79. data/site/_includes/docs_option.html +11 -0
  80. data/site/_includes/docs_ul.html +20 -0
  81. data/site/_includes/footer.html +15 -0
  82. data/site/_includes/header.html +18 -0
  83. data/site/_includes/news_contents.html +23 -0
  84. data/site/_includes/news_contents_mobile.html +11 -0
  85. data/site/_includes/news_item.html +24 -0
  86. data/site/_includes/primary-nav-items.html +14 -0
  87. data/site/_includes/section_nav.html +22 -0
  88. data/site/_includes/top.html +17 -0
  89. data/site/_layouts/default.html +12 -0
  90. data/site/_layouts/docs.html +23 -0
  91. data/site/_layouts/news.html +19 -0
  92. data/site/_layouts/news_item.html +27 -0
  93. data/site/_posts/2013-05-06-jekyll-1-0-0-released.markdown +23 -0
  94. data/site/_posts/2013-05-08-jekyll-1-0-1-released.markdown +27 -0
  95. data/site/_posts/2013-05-12-jekyll-1-0-2-released.markdown +28 -0
  96. data/site/_posts/2013-06-07-jekyll-1-0-3-released.markdown +25 -0
  97. data/site/_posts/2013-07-14-jekyll-1-1-0-released.markdown +27 -0
  98. data/site/_posts/2013-07-24-jekyll-1-1-1-released.markdown +31 -0
  99. data/site/_posts/2013-07-25-jekyll-1-0-4-released.markdown +20 -0
  100. data/site/_posts/2013-07-25-jekyll-1-1-2-released.markdown +20 -0
  101. data/site/_posts/2013-09-06-jekyll-1-2-0-released.markdown +23 -0
  102. data/site/_posts/2013-09-14-jekyll-1-2-1-released.markdown +19 -0
  103. data/site/css/gridism.css +110 -0
  104. data/site/css/normalize.css +1 -0
  105. data/site/css/pygments.css +70 -0
  106. data/site/css/style.css +946 -0
  107. data/site/docs/configuration.md +373 -0
  108. data/site/docs/contributing.md +128 -0
  109. data/site/docs/datafiles.md +63 -0
  110. data/site/docs/deployment-methods.md +109 -0
  111. data/site/docs/drafts.md +20 -0
  112. data/site/docs/extras.md +56 -0
  113. data/site/docs/frontmatter.md +180 -0
  114. data/site/docs/github-pages.md +91 -0
  115. data/site/docs/heroku.md +9 -0
  116. data/site/docs/history.md +722 -0
  117. data/site/docs/index.md +52 -0
  118. data/site/docs/installation.md +76 -0
  119. data/site/docs/migrations.md +257 -0
  120. data/site/docs/pages.md +86 -0
  121. data/site/docs/pagination.md +211 -0
  122. data/site/docs/permalinks.md +180 -0
  123. data/site/docs/plugins.md +508 -0
  124. data/site/docs/posts.md +181 -0
  125. data/site/docs/quickstart.md +32 -0
  126. data/site/docs/resources.md +46 -0
  127. data/site/docs/sites.md +29 -0
  128. data/site/docs/structure.md +190 -0
  129. data/site/docs/templates.md +319 -0
  130. data/site/docs/troubleshooting.md +150 -0
  131. data/site/docs/upgrading.md +146 -0
  132. data/site/docs/usage.md +63 -0
  133. data/site/docs/variables.md +322 -0
  134. data/site/favicon.png +0 -0
  135. data/site/feed.xml +36 -0
  136. data/site/freenode.txt +1 -0
  137. data/site/img/article-footer.png +0 -0
  138. data/site/img/footer-arrow.png +0 -0
  139. data/site/img/footer-logo.png +0 -0
  140. data/site/img/logo-2x.png +0 -0
  141. data/site/img/octojekyll.png +0 -0
  142. data/site/img/tube.png +0 -0
  143. data/site/img/tube1x.png +0 -0
  144. data/site/index.html +90 -0
  145. data/site/js/modernizr-2.5.3.min.js +4 -0
  146. data/site/news/index.html +10 -0
  147. data/site/news/releases/index.html +10 -0
  148. data/test/helper.rb +6 -3
  149. data/test/source/+/foo.md +7 -0
  150. data/test/source/_data/languages.yml +2 -0
  151. data/test/source/_data/members.yaml +7 -0
  152. data/test/source/_data/products.yml +4 -0
  153. data/test/source/_includes/params.html +7 -0
  154. data/test/source/_layouts/default.html +1 -1
  155. data/test/source/_layouts/post/simple.html +1 -0
  156. data/test/source/_plugins/dummy.rb +1 -1
  157. data/test/source/_posts/2013-01-02-post-excerpt.markdown +1 -1
  158. data/test/source/_posts/2013-07-22-post-excerpt-with-layout.markdown +23 -0
  159. data/test/source/_posts/2013-08-01-mkdn-extension.mkdn +0 -0
  160. data/test/source/deal.with.dots.html +1 -1
  161. data/test/source/products.yml +4 -0
  162. data/test/test_configuration.rb +46 -11
  163. data/test/test_convertible.rb +2 -2
  164. data/test/test_excerpt.rb +78 -0
  165. data/test/test_filters.rb +4 -4
  166. data/test/test_generated_site.rb +13 -13
  167. data/test/test_json_driver.rb +9 -9
  168. data/test/test_kramdown.rb +32 -5
  169. data/test/test_new_command.rb +8 -8
  170. data/test/test_page.rb +12 -3
  171. data/test/test_pager.rb +34 -33
  172. data/test/test_post.rb +34 -26
  173. data/test/test_redcloth.rb +3 -3
  174. data/test/test_related_posts.rb +47 -0
  175. data/test/test_site.rb +102 -44
  176. data/test/test_tags.rb +168 -23
  177. data/test/test_url.rb +28 -0
  178. data/test/test_yaml_driver.rb +6 -6
  179. metadata +215 -137
  180. data/lib/monad/commands/doctor.rb +0 -29
  181. data/lib/monad/commands/new.rb +0 -50
  182. data/lib/monad/commands/serve.rb +0 -33
  183. data/lib/monad/converters/markdown/kramdown_parser.rb +0 -44
  184. data/lib/monad/deprecator.rb +0 -32
  185. data/lib/monad/generators/pagination.rb +0 -143
  186. data/lib/monad/logger.rb +0 -54
  187. data/lib/monad/tags/gist.rb +0 -30
  188. data/lib/monad/tags/include.rb +0 -37
@@ -1,15 +1,17 @@
1
+ if RUBY_VERSION > '1.9'
2
+ require 'coveralls'
3
+ Coveralls.wear_merged!
4
+ end
5
+
1
6
  require 'fileutils'
2
7
  require 'rr'
3
8
  require 'test/unit'
9
+ require 'time'
4
10
 
5
- World do
6
- include Test::Unit::Assertions
7
- end
8
-
9
- TEST_DIR = File.join('/', 'tmp', 'monad')
11
+ TEST_DIR = File.join('/', 'tmp', 'jekyll')
10
12
  JEKYLL_PATH = File.join(File.dirname(__FILE__), '..', '..', 'bin', 'monad')
11
13
 
12
- def run_monad(opts = {})
14
+ def run_jekyll(opts = {})
13
15
  command = JEKYLL_PATH.clone
14
16
  command << " build"
15
17
  command << " --drafts" if opts[:drafts]
@@ -17,8 +19,25 @@ def run_monad(opts = {})
17
19
  system command
18
20
  end
19
21
 
20
- def has_time_component?(date_string)
21
- date_string.split(" ").size > 1
22
+ def call_jekyll_new(opts = {})
23
+ command = JEKYLL_PATH.clone
24
+ command << " new"
25
+ command << " #{opts[:path]}" if opts[:path]
26
+ command << " --blank" if opts[:blank]
27
+ command << " >> /dev/null 2>&1" if opts[:debug].nil?
28
+ system command
29
+ end
30
+
31
+ def slug(title)
32
+ title.downcase.gsub(/[^\w]/, " ").strip.gsub(/\s+/, '-')
33
+ end
34
+
35
+ def location(folder, direction)
36
+ if folder
37
+ before = folder if direction == "in"
38
+ after = folder if direction == "under"
39
+ end
40
+ [before || '.', after || '.']
22
41
  end
23
42
 
24
43
  # work around "invalid option: --format" cucumber bug (see #296)
@@ -0,0 +1,99 @@
1
+ $:.unshift File.dirname(__FILE__) # For use/testing when no gem is installed
2
+
3
+ # Require all of the Ruby files in the given directory.
4
+ #
5
+ # path - The String relative path from here to the directory.
6
+ #
7
+ # Returns nothing.
8
+ def require_all(path)
9
+ glob = File.join(File.dirname(__FILE__), path, '*.rb')
10
+ Dir[glob].each do |f|
11
+ require f
12
+ end
13
+ end
14
+
15
+ # rubygems
16
+ require 'rubygems'
17
+
18
+ # stdlib
19
+ require 'fileutils'
20
+ require 'time'
21
+ require 'safe_yaml'
22
+ require 'English'
23
+ require 'pathname'
24
+
25
+ # 3rd party
26
+ require 'liquid'
27
+ require 'maruku'
28
+ require 'colorator'
29
+
30
+ # internal requires
31
+ require 'jekyll/core_ext'
32
+ require 'jekyll/stevenson'
33
+ require 'jekyll/deprecator'
34
+ require 'jekyll/configuration'
35
+ require 'jekyll/site'
36
+ require 'jekyll/convertible'
37
+ require 'jekyll/url'
38
+ require 'jekyll/layout'
39
+ require 'jekyll/page'
40
+ require 'jekyll/post'
41
+ require 'jekyll/excerpt'
42
+ require 'jekyll/draft'
43
+ require 'jekyll/filters'
44
+ require 'jekyll/static_file'
45
+ require 'jekyll/errors'
46
+ require 'jekyll/related_posts'
47
+ require 'jekyll/cleaner'
48
+
49
+ # extensions
50
+ require 'jekyll/plugin'
51
+ require 'jekyll/converter'
52
+ require 'jekyll/generator'
53
+ require 'jekyll/command'
54
+
55
+ require_all 'jekyll/commands'
56
+ require_all 'jekyll/converters'
57
+ require_all 'jekyll/converters/markdown'
58
+ require_all 'jekyll/generators'
59
+ require_all 'jekyll/tags'
60
+ require_all 'jekyll/drivers'
61
+
62
+ SafeYAML::OPTIONS[:suppress_warnings] = true
63
+
64
+ module Jekyll
65
+ VERSION = '1.2.1'
66
+
67
+ # Public: Generate a Jekyll configuration Hash by merging the default
68
+ # options with anything in _config.yml, and adding the given options on top.
69
+ #
70
+ # override - A Hash of config directives that override any options in both
71
+ # the defaults and the config file. See Jekyll::Configuration::DEFAULTS for a
72
+ # list of option names and their defaults.
73
+ #
74
+ # Returns the final configuration Hash.
75
+ def self.configuration(override)
76
+ config = Configuration[Configuration::DEFAULTS]
77
+ override = Configuration[override].stringify_keys
78
+ config = config.read_config_files(config.config_files(override))
79
+
80
+ # Merge DEFAULTS < _config.yml < override
81
+ config = config.deep_merge(override).stringify_keys
82
+ set_timezone(config['timezone']) if config['timezone']
83
+
84
+ config
85
+ end
86
+
87
+ # Static: Set the TZ environment variable to use the timezone specified
88
+ #
89
+ # timezone - the IANA Time Zone
90
+ #
91
+ # Returns nothing
92
+ def self.set_timezone(timezone)
93
+ ENV['TZ'] = timezone
94
+ end
95
+
96
+ def self.logger
97
+ @logger ||= Stevenson.new
98
+ end
99
+ end
@@ -0,0 +1,73 @@
1
+ require 'set'
2
+
3
+ module Jekyll
4
+ class Site
5
+ # Handles the cleanup of a site's destination before it is built.
6
+ class Cleaner
7
+ def initialize(site)
8
+ @site = site
9
+ end
10
+
11
+ # Cleans up the site's destination directory
12
+ def cleanup!
13
+ FileUtils.rm_rf(obsolete_files)
14
+ end
15
+
16
+ private
17
+
18
+ # Private: The list of files and directories to be deleted during cleanup process
19
+ #
20
+ # Returns an Array of the file and directory paths
21
+ def obsolete_files
22
+ (existing_files - new_files - new_dirs + replaced_files).to_a
23
+ end
24
+
25
+ # Private: The list of existing files, apart from those included in keep_files and hidden files.
26
+ #
27
+ # Returns a Set with the file paths
28
+ def existing_files
29
+ files = Set.new
30
+ Dir.glob(File.join(@site.dest, "**", "*"), File::FNM_DOTMATCH) do |file|
31
+ files << file unless file =~ /\/\.{1,2}$/ || file =~ keep_file_regex
32
+ end
33
+ files
34
+ end
35
+
36
+ # Private: The list of files to be created when site is built.
37
+ #
38
+ # Returns a Set with the file paths
39
+ def new_files
40
+ files = Set.new
41
+ @site.each_site_file { |item| files << item.destination(@site.dest) }
42
+ files
43
+ end
44
+
45
+ # Private: The list of directories to be created when site is built.
46
+ # These are the parent directories of the files in #new_files.
47
+ #
48
+ # Returns a Set with the directory paths
49
+ def new_dirs
50
+ new_files.map { |file| File.dirname(file) }.to_set
51
+ end
52
+
53
+ # Private: The list of existing files that will be replaced by a directory during build
54
+ #
55
+ # Returns a Set with the file paths
56
+ def replaced_files
57
+ new_dirs.select { |dir| File.file?(dir) }.to_set
58
+ end
59
+
60
+ # Private: Creates a regular expression from the config's keep_files array
61
+ #
62
+ # Examples
63
+ # ['.git','.svn'] creates the following regex: /\/(\.git|\/.svn)/
64
+ #
65
+ # Returns the regular expression
66
+ def keep_file_regex
67
+ or_list = @site.keep_files.join("|")
68
+ pattern = "\/(#{or_list.gsub(".", "\.")})"
69
+ Regexp.new pattern
70
+ end
71
+ end
72
+ end
73
+ end
@@ -1,4 +1,4 @@
1
- module Monad
1
+ module Jekyll
2
2
  class Command
3
3
  def self.globs(source, destination)
4
4
  Dir.chdir(source) do
@@ -11,16 +11,16 @@ module Monad
11
11
 
12
12
  # Static: Run Site#process and catch errors
13
13
  #
14
- # site - the Monad::Site object
14
+ # site - the Jekyll::Site object
15
15
  #
16
16
  # Returns nothing
17
17
  def self.process_site(site)
18
18
  site.process
19
- rescue Monad::FatalException => e
19
+ rescue Jekyll::FatalException => e
20
20
  puts
21
- Monad::Logger.error "ERROR:", "YOUR SITE COULD NOT BE BUILT:"
22
- Monad::Logger.error "", "------------------------------------"
23
- Monad::Logger.error "", e.message
21
+ Jekyll.logger.error "ERROR:", "YOUR SITE COULD NOT BE BUILT:"
22
+ Jekyll.logger.error "", "------------------------------------"
23
+ Jekyll.logger.error "", e.message
24
24
  exit(1)
25
25
  end
26
26
  end
@@ -1,8 +1,8 @@
1
- module Monad
1
+ module Jekyll
2
2
  module Commands
3
3
  class Build < Command
4
4
  def self.process(options)
5
- site = Monad::Site.new(options)
5
+ site = Jekyll::Site.new(options)
6
6
 
7
7
  self.build(site, options)
8
8
  self.watch(site, options) if options['watch']
@@ -10,23 +10,23 @@ module Monad
10
10
 
11
11
  # Private: Build the site from source into destination.
12
12
  #
13
- # site - A Monad::Site instance
13
+ # site - A Jekyll::Site instance
14
14
  # options - A Hash of options passed to the command
15
15
  #
16
16
  # Returns nothing.
17
17
  def self.build(site, options)
18
18
  source = options['source']
19
19
  destination = options['destination']
20
- Monad::Logger.info "Source:", source
21
- Monad::Logger.info "Destination:", destination
22
- print Monad::Logger.formatted_topic "Generating..."
20
+ Jekyll.logger.info "Source:", source
21
+ Jekyll.logger.info "Destination:", destination
22
+ print Jekyll.logger.formatted_topic "Generating..."
23
23
  self.process_site(site)
24
24
  puts "done."
25
25
  end
26
26
 
27
27
  # Private: Watch for file changes and rebuild the site.
28
28
  #
29
- # site - A Monad::Site instance
29
+ # site - A Jekyll::Site instance
30
30
  # options - A Hash of options passed to the command
31
31
  #
32
32
  # Returns nothing.
@@ -36,14 +36,14 @@ module Monad
36
36
  source = options['source']
37
37
  destination = options['destination']
38
38
 
39
- Monad::Logger.info "Auto-regeneration:", "enabled"
39
+ Jekyll.logger.info "Auto-regeneration:", "enabled"
40
40
 
41
41
  dw = DirectoryWatcher.new(source, :glob => self.globs(source, destination), :pre_load => true)
42
42
  dw.interval = 1
43
43
 
44
44
  dw.add_observer do |*args|
45
45
  t = Time.now.strftime("%Y-%m-%d %H:%M:%S")
46
- print Monad::Logger.formatted_topic("Regenerating:") + "#{args.size} files at #{t} "
46
+ print Jekyll.logger.formatted_topic("Regenerating:") + "#{args.size} files at #{t} "
47
47
  self.process_site(site)
48
48
  puts "...done."
49
49
  end
@@ -0,0 +1,67 @@
1
+ module Jekyll
2
+ module Commands
3
+ class Doctor < Command
4
+ class << self
5
+ def process(options)
6
+ site = Jekyll::Site.new(options)
7
+ site.read
8
+
9
+ if healthy?(site)
10
+ Jekyll.logger.info "Your test results", "are in. Everything looks fine."
11
+ else
12
+ abort
13
+ end
14
+ end
15
+
16
+ def healthy?(site)
17
+ [
18
+ !deprecated_relative_permalinks(site),
19
+ !conflicting_urls(site)
20
+ ].all?
21
+ end
22
+
23
+ def deprecated_relative_permalinks(site)
24
+ contains_deprecated_pages = false
25
+ site.pages.each do |page|
26
+ if page.uses_relative_permalinks
27
+ Jekyll.logger.warn "Deprecation:", "'#{page.path}' uses relative" +
28
+ " permalinks which will be deprecated in" +
29
+ " Jekyll v1.2 and beyond."
30
+ contains_deprecated_pages = true
31
+ end
32
+ end
33
+ contains_deprecated_pages
34
+ end
35
+
36
+ def conflicting_urls(site)
37
+ conflicting_urls = false
38
+ urls = {}
39
+ urls = collect_urls(urls, site.pages, site.dest)
40
+ urls = collect_urls(urls, site.posts, site.dest)
41
+ urls.each do |url, paths|
42
+ if paths.size > 1
43
+ conflicting_urls = true
44
+ Jekyll.logger.warn "Conflict:", "The URL '#{url}' is the destination" +
45
+ " for the following pages: #{paths.join(", ")}"
46
+ end
47
+ end
48
+ conflicting_urls
49
+ end
50
+
51
+ private
52
+
53
+ def collect_urls(urls, things, destination)
54
+ things.each do |thing|
55
+ dest = thing.destination(destination)
56
+ if urls[dest]
57
+ urls[dest] << thing.path
58
+ else
59
+ urls[dest] = [thing.path]
60
+ end
61
+ end
62
+ urls
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,67 @@
1
+ require 'erb'
2
+
3
+ module Jekyll
4
+ module Commands
5
+ class New < Command
6
+ def self.process(args, options = {})
7
+ raise ArgumentError.new('You must specify a path.') if args.empty?
8
+
9
+ new_blog_path = File.expand_path(args.join(" "), Dir.pwd)
10
+ FileUtils.mkdir_p new_blog_path
11
+ if preserve_source_location?(new_blog_path, options)
12
+ Jekyll.logger.error "Conflict:", "#{new_blog_path} exists and is not empty."
13
+ exit(1)
14
+ end
15
+
16
+ if options[:blank]
17
+ create_blank_site new_blog_path
18
+ else
19
+ create_sample_files new_blog_path
20
+
21
+ File.open(File.expand_path(self.initialized_post_name, new_blog_path), "w") do |f|
22
+ f.write(self.scaffold_post_content)
23
+ end
24
+ end
25
+
26
+ puts "New jekyll site installed in #{new_blog_path}."
27
+ end
28
+
29
+ def self.create_blank_site(path)
30
+ Dir.chdir(path) do
31
+ FileUtils.mkdir(%w(_layouts _posts _drafts))
32
+ FileUtils.touch("index.html")
33
+ end
34
+ end
35
+
36
+ def self.scaffold_post_content
37
+ ERB.new(File.read(File.expand_path(scaffold_path, site_template))).result
38
+ end
39
+
40
+ # Internal: Gets the filename of the sample post to be created
41
+ #
42
+ # Returns the filename of the sample post, as a String
43
+ def self.initialized_post_name
44
+ "_posts/#{Time.now.strftime('%Y-%m-%d')}-welcome-to-jekyll.markdown"
45
+ end
46
+
47
+ private
48
+
49
+ def self.preserve_source_location?(path, options)
50
+ !options[:force] && !Dir["#{path}/**/*"].empty?
51
+ end
52
+
53
+ def self.create_sample_files(path)
54
+ FileUtils.cp_r site_template + '/.', path
55
+ FileUtils.rm File.expand_path(scaffold_path, path)
56
+ end
57
+
58
+ def self.site_template
59
+ File.expand_path("../../site_template", File.dirname(__FILE__))
60
+ end
61
+
62
+ def self.scaffold_path
63
+ "_posts/0000-00-00-welcome-to-jekyll.markdown.erb"
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,65 @@
1
+ # -*- encoding: utf-8 -*-
2
+ module Jekyll
3
+ module Commands
4
+ class Serve < Command
5
+ def self.process(options)
6
+ require 'webrick'
7
+ include WEBrick
8
+
9
+ destination = options['destination']
10
+
11
+ FileUtils.mkdir_p(destination)
12
+
13
+ # recreate NondisclosureName under utf-8 circumstance
14
+ fh_option = WEBrick::Config::FileHandler
15
+ fh_option[:NondisclosureName] = ['.ht*','~*']
16
+
17
+ s = HTTPServer.new(webrick_options(options))
18
+
19
+ s.mount(options['baseurl'], HTTPServlet::FileHandler, destination, fh_option)
20
+
21
+ Jekyll.logger.info "Server address:", "http://#{s.config[:BindAddress]}:#{s.config[:Port]}"
22
+
23
+ if options['detach'] # detach the server
24
+ pid = Process.fork { s.start }
25
+ Process.detach(pid)
26
+ Jekyll.logger.info "Server detatched with pid '#{pid}'.", "Run `kill -9 #{pid}' to stop the server."
27
+ else # create a new server thread, then join it with current terminal
28
+ t = Thread.new { s.start }
29
+ trap("INT") { s.shutdown }
30
+ t.join()
31
+ end
32
+ end
33
+
34
+ def self.webrick_options(config)
35
+ opts = {
36
+ :Port => config['port'],
37
+ :BindAddress => config['host'],
38
+ :MimeTypes => self.mime_types,
39
+ :DoNotReverseLookup => true,
40
+ :StartCallback => start_callback(config['detach'])
41
+ }
42
+
43
+ if !config['verbose']
44
+ opts.merge!({
45
+ :AccessLog => [],
46
+ :Logger => Log::new([], Log::WARN)
47
+ })
48
+ end
49
+
50
+ opts
51
+ end
52
+
53
+ def self.start_callback(detached)
54
+ unless detached
55
+ Proc.new { Jekyll.logger.info "Server running...", "press ctrl-c to stop." }
56
+ end
57
+ end
58
+
59
+ def self.mime_types
60
+ mime_types_file = File.expand_path('../mime.types', File.dirname(__FILE__))
61
+ WEBrick::HTTPUtils::load_mime_types(mime_types_file)
62
+ end
63
+ end
64
+ end
65
+ end