diff --git a/bin/jekyll b/bin/jekyll index 1f3a9c8d..1dacb29b 100755 --- a/bin/jekyll +++ b/bin/jekyll @@ -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' diff --git a/jekyll.gemspec b/jekyll.gemspec index 785c185f..c93639c5 100644 --- a/jekyll.gemspec +++ b/jekyll.gemspec @@ -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 diff --git a/lib/jekyll/commands/new.rb b/lib/jekyll/commands/new.rb new file mode 100644 index 00000000..e650dc52 --- /dev/null +++ b/lib/jekyll/commands/new.rb @@ -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 diff --git a/lib/site_template/_config.yml b/lib/site_template/_config.yml new file mode 100644 index 00000000..6d67c09e --- /dev/null +++ b/lib/site_template/_config.yml @@ -0,0 +1,2 @@ +markdown: rdiscount +pygments: true diff --git a/lib/site_template/_layouts/default.html b/lib/site_template/_layouts/default.html new file mode 100644 index 00000000..9fc00095 --- /dev/null +++ b/lib/site_template/_layouts/default.html @@ -0,0 +1,38 @@ + + + + + {{ page.title }} + + + + + + +
+
+ Your Name + home +
+ + {{ content }} + + +
+ Fork me on GitHub + + diff --git a/lib/site_template/_layouts/post.html b/lib/site_template/_layouts/post.html new file mode 100644 index 00000000..0b28e6bd --- /dev/null +++ b/lib/site_template/_layouts/post.html @@ -0,0 +1,6 @@ +--- +layout: default +--- +
+{{ content }} +
diff --git a/lib/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb b/lib/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb new file mode 100644 index 00000000..c500b41a --- /dev/null +++ b/lib/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb @@ -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 diff --git a/lib/site_template/css/screen.css b/lib/site_template/css/screen.css new file mode 100644 index 00000000..7a230ede --- /dev/null +++ b/lib/site_template/css/screen.css @@ -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; + } diff --git a/lib/site_template/css/syntax.css b/lib/site_template/css/syntax.css new file mode 100644 index 00000000..2774b764 --- /dev/null +++ b/lib/site_template/css/syntax.css @@ -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 */ diff --git a/lib/site_template/images/.gitkeep b/lib/site_template/images/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/lib/site_template/images/rss.png b/lib/site_template/images/rss.png new file mode 100644 index 00000000..d6ecb16f Binary files /dev/null and b/lib/site_template/images/rss.png differ diff --git a/lib/site_template/index.html b/lib/site_template/index.html new file mode 100644 index 00000000..c7268192 --- /dev/null +++ b/lib/site_template/index.html @@ -0,0 +1,13 @@ +--- +layout: default +title: Your New Jekyll Site +--- + +
+

Blog Posts

+ +
\ No newline at end of file diff --git a/test/test_new_command.rb b/test/test_new_command.rb new file mode 100644 index 00000000..bc9e6585 --- /dev/null +++ b/test/test_new_command.rb @@ -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