monad 0.0.2 → 0.0.3

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.
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