Merge pull request #764 from mojombo/jekyll-new
`jekyll new`: scaffold site generator
This commit is contained in:
		
						commit
						e2d0697f30
					
				|  | @ -30,6 +30,15 @@ def normalize_options(options) | |||
|   options | ||||
| end | ||||
| 
 | ||||
| command :new do |c| | ||||
|   c.syntax = 'jekyll new PATH' | ||||
|   c.description = 'Creates a new Jekyll site scaffold in PATH' | ||||
| 
 | ||||
|   c.action do |args, options| | ||||
|     Jekyll::Commands::New.process(args) | ||||
|   end | ||||
| end | ||||
| 
 | ||||
| command :build do |c| | ||||
|   c.syntax = 'jekyll build [options]' | ||||
|   c.description = 'Build your site' | ||||
|  |  | |||
|  | @ -70,6 +70,8 @@ Gem::Specification.new do |s| | |||
|     lib/jekyll.rb | ||||
|     lib/jekyll/command.rb | ||||
|     lib/jekyll/commands/build.rb | ||||
|     lib/jekyll/commands/migrate.rb | ||||
|     lib/jekyll/commands/new.rb | ||||
|     lib/jekyll/commands/serve.rb | ||||
|     lib/jekyll/converter.rb | ||||
|     lib/jekyll/converters/identity.rb | ||||
|  | @ -93,6 +95,15 @@ Gem::Specification.new do |s| | |||
|     lib/jekyll/tags/highlight.rb | ||||
|     lib/jekyll/tags/include.rb | ||||
|     lib/jekyll/tags/post_url.rb | ||||
|     lib/site_template/_config.yml | ||||
|     lib/site_template/_layouts/default.html | ||||
|     lib/site_template/_layouts/post.html | ||||
|     lib/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb | ||||
|     lib/site_template/css/screen.css | ||||
|     lib/site_template/css/syntax.css | ||||
|     lib/site_template/images/.gitkeep | ||||
|     lib/site_template/images/rss.png | ||||
|     lib/site_template/index.html | ||||
|     script/bootstrap | ||||
|     site/.gitignore | ||||
|     site/CNAME | ||||
|  |  | |||
|  | @ -0,0 +1,46 @@ | |||
| require 'erb' | ||||
| 
 | ||||
| module Jekyll | ||||
|   module Commands | ||||
|     class New < Command | ||||
|       def self.process(args) | ||||
|         raise ArgumentError.new('You must specify a path.') if args.empty? | ||||
| 
 | ||||
|         new_blog_path = File.expand_path(args.join(" "), Dir.pwd) | ||||
|         FileUtils.mkdir_p new_blog_path | ||||
| 
 | ||||
|         create_sample_files new_blog_path | ||||
| 
 | ||||
|         File.open(File.expand_path(self.initialized_post_name, new_blog_path), "w") do |f| | ||||
|           f.write(self.scaffold_post_content(site_template)) | ||||
|         end | ||||
|         puts "New jekyll site installed in #{new_blog_path}." | ||||
|       end | ||||
| 
 | ||||
|       def self.scaffold_post_content(template_site) | ||||
|         ERB.new(File.read(File.expand_path(scaffold_path, site_template))).result | ||||
|       end | ||||
| 
 | ||||
|       # Internal: Gets the filename of the sample post to be created | ||||
|       # | ||||
|       # Returns the filename of the sample post, as a String | ||||
|       def self.initialized_post_name | ||||
|         "_posts/#{Time.now.strftime('%Y-%m-%d')}-welcome-to-jekyll.markdown" | ||||
|       end | ||||
| 
 | ||||
|       private | ||||
|       def self.create_sample_files(path) | ||||
|         FileUtils.cp_r site_template + '/.', path | ||||
|         FileUtils.rm File.expand_path(scaffold_path, path) | ||||
|       end | ||||
| 
 | ||||
|       def self.site_template | ||||
|         File.expand_path("../../site_template", File.dirname(__FILE__)) | ||||
|       end | ||||
| 
 | ||||
|       def self.scaffold_path | ||||
|         "_posts/0000-00-00-welcome-to-jekyll.markdown.erb" | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | @ -0,0 +1,2 @@ | |||
| markdown: rdiscount | ||||
| pygments: true | ||||
|  | @ -0,0 +1,38 @@ | |||
| <!DOCTYPE html> | ||||
| <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en-us"> | ||||
| <head> | ||||
|    <meta http-equiv="content-type" content="text/html; charset=utf-8" /> | ||||
|    <title>{{ page.title }}</title> | ||||
|    <!-- syntax highlighting CSS --> | ||||
|    <link rel="stylesheet" href="/css/syntax.css" type="text/css" /> | ||||
|    <!-- Homepage CSS --> | ||||
|    <link rel="stylesheet" href="/css/screen.css" type="text/css" media="screen, projection" /> | ||||
| </head> | ||||
| <body> | ||||
|   <div class="site"> | ||||
|     <div class="title"> | ||||
|       <a href="/">Your Name</a> | ||||
|       <a class="extra" href="/">home</a> | ||||
|     </div> | ||||
|    | ||||
|     {{ content }} | ||||
|    | ||||
|     <div class="footer"> | ||||
|       <div class="contact"> | ||||
|         <p> | ||||
|           Your Name<br /> | ||||
|           What You Are<br /> | ||||
|           your@email.com | ||||
|         </p> | ||||
|       </div> | ||||
|       <div class="contact"> | ||||
|         <p> | ||||
|           <a href="http://github.com/yourusername/">github.com/yourusername</a><br /> | ||||
|           <a href="http://twitter.com/yourusername/">twitter.com/yourusername</a><br /> | ||||
|         </p> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
|   <a href="http://github.com/yourusername"><img style="position: absolute; top: 0; right: 0; border: 0;" src="http://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" /></a> | ||||
| </body> | ||||
| </html> | ||||
|  | @ -0,0 +1,6 @@ | |||
| --- | ||||
| layout: default | ||||
| --- | ||||
| <div id="post"> | ||||
| {{ content }} | ||||
| </div> | ||||
|  | @ -0,0 +1,24 @@ | |||
| --- | ||||
| layout: post | ||||
| title:  "Welcome to Jekyll!" | ||||
| date:   <%= Time.now.strftime('%Y-%m-%d %H:%M:%S') %> | ||||
| categories: jekyll update | ||||
| --- | ||||
| 
 | ||||
| You'll find this post in your `_posts` directory - edit this post and re-build (or run with the `-w` switch) to see your changes! | ||||
| To add new posts, simply add a file in the `_posts` directory that follows the convention: YYYY-MM-DD-name-of-post.ext. | ||||
| 
 | ||||
| Jekyll also offers powerful support for code snippets: | ||||
| 
 | ||||
| {% highlight ruby %} | ||||
| def print_hi(name) | ||||
|   puts "Hi, #{name}" | ||||
| end | ||||
| print_hi('Tom') | ||||
| #=> prints 'Hi, Tom' to STDOUT. | ||||
| {% endhighlight %} | ||||
| 
 | ||||
| Check out the [Jekyll docs][jekyll] for more info on how to get the most out of Jekyll. File all bugs/feature requests at [Jekyll's GitHub repo][jekyll-gh]. | ||||
| 
 | ||||
| [jekyll-gh]: https://github.com/mojombo/jekyll | ||||
| [jekyll]:    http://jekyllrb.com | ||||
|  | @ -0,0 +1,189 @@ | |||
| /*****************************************************************************/ | ||||
| /* | ||||
| /* Common | ||||
| /* | ||||
| /*****************************************************************************/ | ||||
| 
 | ||||
| /* Global Reset */ | ||||
| 
 | ||||
| * { | ||||
|   margin: 0; | ||||
|   padding: 0; | ||||
| } | ||||
| 
 | ||||
| html, body { | ||||
|   height: 100%; | ||||
| } | ||||
| 
 | ||||
| body { | ||||
|   background-color: white; | ||||
|   font: 13.34px helvetica, arial, clean, sans-serif; | ||||
|   *font-size: small; | ||||
|   text-align: center; | ||||
| } | ||||
| 
 | ||||
| h1, h2, h3, h4, h5, h6 { | ||||
|   font-size: 100%; | ||||
| } | ||||
| 
 | ||||
| h1 { | ||||
|   margin-bottom: 1em; | ||||
| } | ||||
| 
 | ||||
| p { | ||||
|   margin: 1em 0; | ||||
| } | ||||
| 
 | ||||
| a { | ||||
|   color: #00a; | ||||
| } | ||||
| 
 | ||||
| a:hover { | ||||
|   color: black; | ||||
| } | ||||
| 
 | ||||
| a:visited { | ||||
|   color: #a0a; | ||||
| } | ||||
| 
 | ||||
| table { | ||||
|   font-size: inherit; | ||||
|   font: 100%; | ||||
| } | ||||
| 
 | ||||
| /*****************************************************************************/ | ||||
| /* | ||||
| /* Home | ||||
| /* | ||||
| /*****************************************************************************/ | ||||
| 
 | ||||
| ul.posts { | ||||
|   list-style-type: none; | ||||
|   margin-bottom: 2em; | ||||
| } | ||||
| 
 | ||||
|   ul.posts li { | ||||
|     line-height: 1.75em; | ||||
|   } | ||||
| 
 | ||||
|   ul.posts span { | ||||
|     color: #aaa; | ||||
|     font-family: Monaco, "Courier New", monospace; | ||||
|     font-size: 80%; | ||||
|   } | ||||
| 
 | ||||
| /*****************************************************************************/ | ||||
| /* | ||||
| /* Site | ||||
| /* | ||||
| /*****************************************************************************/ | ||||
| 
 | ||||
| .site { | ||||
|   font-size: 110%; | ||||
|   text-align: justify; | ||||
|   width: 42em; | ||||
|   margin: 3em auto 2em auto; | ||||
|   line-height: 1.5em; | ||||
| } | ||||
| 
 | ||||
| .title { | ||||
|   color: #a00; | ||||
|   font-weight: bold; | ||||
|   margin-bottom: 2em; | ||||
| } | ||||
| 
 | ||||
|   .site .title a { | ||||
|     color: #a00; | ||||
|     text-decoration: none; | ||||
|   } | ||||
| 
 | ||||
|   .site .title a:hover { | ||||
|     color: black; | ||||
|   } | ||||
| 
 | ||||
|   .site .title a.extra { | ||||
|     color: #aaa; | ||||
|     text-decoration: none; | ||||
|     margin-left: 1em; | ||||
|   } | ||||
| 
 | ||||
|   .site .title a.extra:hover { | ||||
|     color: black; | ||||
|   } | ||||
| 
 | ||||
|   .site .meta { | ||||
|     color: #aaa; | ||||
|   } | ||||
| 
 | ||||
|   .site .footer { | ||||
|     font-size: 80%; | ||||
|     color: #666; | ||||
|     border-top: 4px solid #eee; | ||||
|     margin-top: 2em; | ||||
|     overflow: hidden; | ||||
|   } | ||||
| 
 | ||||
|     .site .footer .contact { | ||||
|       float: left; | ||||
|       margin-right: 3em; | ||||
|     } | ||||
| 
 | ||||
|       .site .footer .contact a { | ||||
|         color: #8085C1; | ||||
|       } | ||||
| 
 | ||||
|     .site .footer .rss { | ||||
|       margin-top: 1.1em; | ||||
|       margin-right: -.2em; | ||||
|       float: right; | ||||
|     } | ||||
| 
 | ||||
|       .site .footer .rss img { | ||||
|         border: 0; | ||||
|       } | ||||
| 
 | ||||
| /*****************************************************************************/ | ||||
| /* | ||||
| /* Posts | ||||
| /* | ||||
| /*****************************************************************************/ | ||||
| 
 | ||||
| #post { | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
|   /* standard */ | ||||
| 
 | ||||
|   #post pre { | ||||
|     border: 1px solid #ddd; | ||||
|     background-color: #eef; | ||||
|     padding: 0 .4em; | ||||
|   } | ||||
| 
 | ||||
|   #post ul, | ||||
|   #post ol { | ||||
|     margin-left: 1.35em; | ||||
|   } | ||||
| 
 | ||||
|   #post code { | ||||
|     border: 1px solid #ddd; | ||||
|     background-color: #eef; | ||||
|     font-size: 85%; | ||||
|     padding: 0 .2em; | ||||
|   } | ||||
| 
 | ||||
|     #post pre code { | ||||
|       border: none; | ||||
|     } | ||||
| 
 | ||||
|   /* terminal */ | ||||
| 
 | ||||
|   #post pre.terminal { | ||||
|     border: 1px solid black; | ||||
|     background-color: #333; | ||||
|     color: white; | ||||
|   } | ||||
| 
 | ||||
|   #post pre.terminal code { | ||||
|     background-color: #333; | ||||
|   } | ||||
|  | @ -0,0 +1,60 @@ | |||
| .highlight  { background: #ffffff; } | ||||
| .highlight .c { color: #999988; font-style: italic } /* Comment */ | ||||
| .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ | ||||
| .highlight .k { font-weight: bold } /* Keyword */ | ||||
| .highlight .o { font-weight: bold } /* Operator */ | ||||
| .highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */ | ||||
| .highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */ | ||||
| .highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */ | ||||
| .highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */ | ||||
| .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ | ||||
| .highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */ | ||||
| .highlight .ge { font-style: italic } /* Generic.Emph */ | ||||
| .highlight .gr { color: #aa0000 } /* Generic.Error */ | ||||
| .highlight .gh { color: #999999 } /* Generic.Heading */ | ||||
| .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ | ||||
| .highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */ | ||||
| .highlight .go { color: #888888 } /* Generic.Output */ | ||||
| .highlight .gp { color: #555555 } /* Generic.Prompt */ | ||||
| .highlight .gs { font-weight: bold } /* Generic.Strong */ | ||||
| .highlight .gu { color: #aaaaaa } /* Generic.Subheading */ | ||||
| .highlight .gt { color: #aa0000 } /* Generic.Traceback */ | ||||
| .highlight .kc { font-weight: bold } /* Keyword.Constant */ | ||||
| .highlight .kd { font-weight: bold } /* Keyword.Declaration */ | ||||
| .highlight .kp { font-weight: bold } /* Keyword.Pseudo */ | ||||
| .highlight .kr { font-weight: bold } /* Keyword.Reserved */ | ||||
| .highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */ | ||||
| .highlight .m { color: #009999 } /* Literal.Number */ | ||||
| .highlight .s { color: #d14 } /* Literal.String */ | ||||
| .highlight .na { color: #008080 } /* Name.Attribute */ | ||||
| .highlight .nb { color: #0086B3 } /* Name.Builtin */ | ||||
| .highlight .nc { color: #445588; font-weight: bold } /* Name.Class */ | ||||
| .highlight .no { color: #008080 } /* Name.Constant */ | ||||
| .highlight .ni { color: #800080 } /* Name.Entity */ | ||||
| .highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */ | ||||
| .highlight .nf { color: #990000; font-weight: bold } /* Name.Function */ | ||||
| .highlight .nn { color: #555555 } /* Name.Namespace */ | ||||
| .highlight .nt { color: #000080 } /* Name.Tag */ | ||||
| .highlight .nv { color: #008080 } /* Name.Variable */ | ||||
| .highlight .ow { font-weight: bold } /* Operator.Word */ | ||||
| .highlight .w { color: #bbbbbb } /* Text.Whitespace */ | ||||
| .highlight .mf { color: #009999 } /* Literal.Number.Float */ | ||||
| .highlight .mh { color: #009999 } /* Literal.Number.Hex */ | ||||
| .highlight .mi { color: #009999 } /* Literal.Number.Integer */ | ||||
| .highlight .mo { color: #009999 } /* Literal.Number.Oct */ | ||||
| .highlight .sb { color: #d14 } /* Literal.String.Backtick */ | ||||
| .highlight .sc { color: #d14 } /* Literal.String.Char */ | ||||
| .highlight .sd { color: #d14 } /* Literal.String.Doc */ | ||||
| .highlight .s2 { color: #d14 } /* Literal.String.Double */ | ||||
| .highlight .se { color: #d14 } /* Literal.String.Escape */ | ||||
| .highlight .sh { color: #d14 } /* Literal.String.Heredoc */ | ||||
| .highlight .si { color: #d14 } /* Literal.String.Interpol */ | ||||
| .highlight .sx { color: #d14 } /* Literal.String.Other */ | ||||
| .highlight .sr { color: #009926 } /* Literal.String.Regex */ | ||||
| .highlight .s1 { color: #d14 } /* Literal.String.Single */ | ||||
| .highlight .ss { color: #990073 } /* Literal.String.Symbol */ | ||||
| .highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */ | ||||
| .highlight .vc { color: #008080 } /* Name.Variable.Class */ | ||||
| .highlight .vg { color: #008080 } /* Name.Variable.Global */ | ||||
| .highlight .vi { color: #008080 } /* Name.Variable.Instance */ | ||||
| .highlight .il { color: #009999 } /* Literal.Number.Integer.Long */ | ||||
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 5.0 KiB | 
|  | @ -0,0 +1,13 @@ | |||
| --- | ||||
| layout: default | ||||
| title: Your New Jekyll Site | ||||
| --- | ||||
| 
 | ||||
| <div id="home"> | ||||
|   <h1>Blog Posts</h1> | ||||
|   <ul class="posts"> | ||||
|     {% for post in site.posts %} | ||||
|       <li><span>{{ post.date | date_to_string }}</span> » <a href="{{ post.url }}">{{ post.title }}</a></li> | ||||
|     {% endfor %} | ||||
|   </ul> | ||||
| </div> | ||||
|  | @ -0,0 +1,104 @@ | |||
| require 'helper' | ||||
| require 'jekyll/commands/new' | ||||
| 
 | ||||
| class TestNewCommand < Test::Unit::TestCase | ||||
|   def dir_contents(path) | ||||
|     Dir["#{path}/**/*"].each do |file| | ||||
|       file.gsub! path, '' | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def site_template | ||||
|     File.expand_path("../lib/site_template", File.dirname(__FILE__)) | ||||
|   end | ||||
| 
 | ||||
|   context 'when args contains a path' do | ||||
|     setup do | ||||
|       @path = 'new-site' | ||||
|       @args = [@path] | ||||
|       @full_path = File.expand_path(@path, Dir.pwd) | ||||
|     end | ||||
| 
 | ||||
|     teardown do | ||||
|       FileUtils.rm_r @full_path | ||||
|     end | ||||
| 
 | ||||
|     should 'create a new directory' do | ||||
|       assert !File.exists?(@full_path) | ||||
|       capture_stdout { Jekyll::Commands::New.process(@args) } | ||||
|       assert File.exists?(@full_path) | ||||
|     end | ||||
| 
 | ||||
|     should 'display a success message' do | ||||
|       output = capture_stdout { Jekyll::Commands::New.process(@args) } | ||||
|       success_message = "New jekyll site installed in #{@full_path}.\n" | ||||
|       assert_equal success_message, output | ||||
|     end | ||||
| 
 | ||||
|     should 'copy the static files in site template to the new directory' do | ||||
|       static_template_files = dir_contents(site_template).reject do |f| | ||||
|         File.extname(f) == '.erb' | ||||
|       end | ||||
| 
 | ||||
|       capture_stdout { Jekyll::Commands::New.process(@args) } | ||||
| 
 | ||||
|       new_site_files = dir_contents(@full_path).reject do |f| | ||||
|         File.extname(f) == '.markdown' | ||||
|       end | ||||
| 
 | ||||
|       assert_same_elements static_template_files, new_site_files | ||||
|     end | ||||
| 
 | ||||
|     should 'process any ERB files' do | ||||
|       erb_template_files = dir_contents(site_template).select do |f| | ||||
|         File.extname(f) == '.erb' | ||||
|       end | ||||
| 
 | ||||
|       stubbed_date = '2013-01-01' | ||||
|       stub.instance_of(Time).strftime { stubbed_date } | ||||
| 
 | ||||
|       erb_template_files.each do |f| | ||||
|         f.chomp! '.erb' | ||||
|         f.gsub! '0000-00-00', stubbed_date | ||||
|       end | ||||
| 
 | ||||
|       capture_stdout { Jekyll::Commands::New.process(@args) } | ||||
| 
 | ||||
|       new_site_files = dir_contents(@full_path).select do |f| | ||||
|         erb_template_files.include? f | ||||
|       end | ||||
| 
 | ||||
|       assert_same_elements erb_template_files, new_site_files | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   context 'when multiple args are given' do | ||||
|     setup do | ||||
|       @site_name_with_spaces = 'new site name' | ||||
|       @multiple_args = @site_name_with_spaces.split | ||||
|     end | ||||
| 
 | ||||
|     teardown do | ||||
|       FileUtils.rm_r File.expand_path(@site_name_with_spaces, Dir.pwd) | ||||
|     end | ||||
| 
 | ||||
|     should 'create a new directory' do | ||||
|       assert !File.exists?(@site_name_with_spaces) | ||||
|       capture_stdout { Jekyll::Commands::New.process(@multiple_args) } | ||||
|       assert File.exists?(@site_name_with_spaces) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   context 'when no args are given' do | ||||
|     setup do | ||||
|       @empty_args = [] | ||||
|     end | ||||
| 
 | ||||
|     should 'raise an ArgumentError' do | ||||
|       exception = assert_raise ArgumentError do | ||||
|         Jekyll::Commands::New.process(@empty_args) | ||||
|       end | ||||
|       assert_equal 'You must specify a path.', exception.message | ||||
|     end | ||||
|   end | ||||
| end | ||||
		Loading…
	
		Reference in New Issue