diff --git a/History.markdown b/History.markdown index 3169037..dfd136e 100644 --- a/History.markdown +++ b/History.markdown @@ -1,7 +1,8 @@ ## HEAD - * Commands will create directories if necessary (#17, #23) * Add the `page` command (#15) + * Add the `unpublish` command (#21) + * Commands will create directories if necessary (#17, #23) * Display relative directories without ./ (#22) * Change `-t`, `--type` options to `-x`, `--extension` (#25) diff --git a/lib/jekyll-compose.rb b/lib/jekyll-compose.rb index cbe813c..c760480 100644 --- a/lib/jekyll-compose.rb +++ b/lib/jekyll-compose.rb @@ -1,6 +1,8 @@ require "jekyll-compose/version" require "jekyll-compose/arg_parser" +require "jekyll-compose/movement_arg_parser" require "jekyll-compose/file_creator" +require "jekyll-compose/file_mover" require "jekyll-compose/file_info" module Jekyll @@ -11,6 +13,6 @@ module Compose end end -%w{draft post publish page}.each do |file| +%w{draft post publish unpublish page}.each do |file| require File.expand_path("jekyll/commands/#{file}.rb", File.dirname(__FILE__)) end diff --git a/lib/jekyll-compose/file_mover.rb b/lib/jekyll-compose/file_mover.rb new file mode 100644 index 0000000..7bc67ee --- /dev/null +++ b/lib/jekyll-compose/file_mover.rb @@ -0,0 +1,34 @@ +module Jekyll + module Compose + class FileMover + attr_reader :movement + def initialize(movement) + @movement = movement + end + + def resource_type + 'file' + end + + def move + validate_source + ensure_directory_exists + move_file + end + + def validate_source + raise ArgumentError.new("There was no #{resource_type} found at '#{movement.from}'.") unless File.exist? movement.from + end + + def ensure_directory_exists + dir = File.dirname movement.to + Dir.mkdir(dir) unless Dir.exist?(dir) + end + + def move_file + FileUtils.mv(movement.from, movement.to) + puts "#{resource_type.capitalize} #{movement.from} was moved to #{movement.to}" + end + end + end +end diff --git a/lib/jekyll-compose/movement_arg_parser.rb b/lib/jekyll-compose/movement_arg_parser.rb new file mode 100644 index 0000000..903cac3 --- /dev/null +++ b/lib/jekyll-compose/movement_arg_parser.rb @@ -0,0 +1,19 @@ +module Jekyll + module Compose + class MovementArgParser + attr_reader :args, :options + def initialize(args, options) + @args = args + @options = options + end + + def validate! + raise ArgumentError.new("You must specify a #{resource_type} path.") if args.empty? + end + + def path + args.join ' ' + end + end + end +end diff --git a/lib/jekyll/commands/post.rb b/lib/jekyll/commands/post.rb index a834580..2635059 100644 --- a/lib/jekyll/commands/post.rb +++ b/lib/jekyll/commands/post.rb @@ -33,7 +33,7 @@ def self.process(args = [], options = {}) class PostArgParser < Compose::ArgParser def date - date = options["date"].nil? ? Time.now : DateTime.parse(options["date"]) + options["date"].nil? ? Time.now : DateTime.parse(options["date"]) end end diff --git a/lib/jekyll/commands/publish.rb b/lib/jekyll/commands/publish.rb index 91289b9..8a14cbb 100644 --- a/lib/jekyll/commands/publish.rb +++ b/lib/jekyll/commands/publish.rb @@ -15,31 +15,51 @@ def self.init_with_program(prog) end def self.process(args = [], options = {}) - raise ArgumentError.new('You must specify a draft path.') if args.empty? + params = PublishArgParser.new args, options + params.validate! - date = options["date"].nil? ? Date.today : Date.parse(options["date"]) - draft_path = args.shift + movement = DraftMovementInfo.new params - raise ArgumentError.new("There was no draft found at '#{draft_path}'.") unless File.exist? draft_path + mover = DraftMover.new movement + mover.move + end + + end - Dir.mkdir("_posts") unless Dir.exist?("_posts") - post_path = post_name(date, draft_name(draft_path)) - FileUtils.mv(draft_path, post_path) + class PublishArgParser < Compose::MovementArgParser + def resource_type + "draft" + end - puts "Draft #{draft_path} was published to #{post_path}" + def date + options["date"].nil? ? Date.today : Date.parse(options["date"]) end - # Internal: Gets the filename of the post to be created - # - # Returns the filename of the post, as a String - def self.post_name(date, name) - "_posts/#{date.strftime('%Y-%m-%d')}-#{name}" + def name + File.basename path end + end - def self.draft_name(path) - File.basename(path) + class DraftMovementInfo + attr_reader :params + def initialize(params) + @params = params end + def from + params.path + end + + def to + date_stamp = params.date.strftime '%Y-%m-%d' + "_posts/#{date_stamp}-#{params.name}" + end + end + + class DraftMover < Compose::FileMover + def resource_type + 'draft' + end end end end diff --git a/lib/jekyll/commands/unpublish.rb b/lib/jekyll/commands/unpublish.rb new file mode 100644 index 0000000..8ce0b32 --- /dev/null +++ b/lib/jekyll/commands/unpublish.rb @@ -0,0 +1,58 @@ +module Jekyll + module Commands + class Unpublish < Command + def self.init_with_program(prog) + prog.command(:unpublish) do |c| + c.syntax 'unpublish POST_PATH' + c.description 'Moves a post back into the _drafts directory' + + c.action do |args, options| + process(args, options) + end + end + end + + def self.process(args = [], options = {}) + params = UnpublishArgParser.new args, options + params.validate! + + movement = PostMovementInfo.new params + + mover = PostMover.new movement + mover.move + end + + end + + class UnpublishArgParser < Compose::MovementArgParser + def resource_type + 'post' + end + + def name + File.basename(path).sub /\d{4}-\d{2}-\d{2}-/, '' + end + end + + class PostMovementInfo + attr_reader :params + def initialize(params) + @params = params + end + + def from + params.path + end + + def to + "_drafts/#{params.name}" + end + end + + class PostMover < Compose::FileMover + def resource_type + 'post' + end + end + end +end diff --git a/spec/publish_spec.rb b/spec/publish_spec.rb index 3887207..c1e1a6e 100644 --- a/spec/publish_spec.rb +++ b/spec/publish_spec.rb @@ -1,13 +1,13 @@ RSpec.describe(Jekyll::Commands::Publish) do - let(:drafts_dir) { source_dir('_drafts') } - let(:posts_dir) { source_dir('_posts') } + let(:drafts_dir) { Pathname.new source_dir('_drafts') } + let(:posts_dir) { Pathname.new source_dir('_posts') } let(:draft_to_publish) { 'a-test-post.md' } let(:datestamp) { Time.now.strftime('%Y-%m-%d') } let(:post_filename) { "#{datestamp}-#{draft_to_publish}" } let(:args) { ["_drafts/#{draft_to_publish}"] } - let(:draft_path) { Pathname.new(File.join(drafts_dir, draft_to_publish)) } - let(:post_path) { Pathname.new(File.join(posts_dir, post_filename))} + let(:draft_path) { drafts_dir.join draft_to_publish } + let(:post_path) { posts_dir.join post_filename } before(:all) do FileUtils.mkdir_p source_dir unless File.directory? source_dir @@ -28,20 +28,27 @@ end it 'publishes a draft post' do - expect(Pathname.new(post_path)).not_to exist - expect(Pathname.new(draft_path)).to exist + expect(post_path).not_to exist + expect(draft_path).to exist capture_stdout { described_class.process(args) } - expect(Pathname.new(post_path)).to exist + expect(post_path).to exist + end + + it 'publishes with a specified date' do + path = posts_dir.join "2012-03-04-#{draft_to_publish}" + expect(path).not_to exist + capture_stdout { described_class.process(args, {'date'=>'2012-3-4'}) } + expect(path).to exist end it 'writes a helpful message on success' do - expect(Pathname.new(draft_path)).to exist + expect(draft_path).to exist output = capture_stdout { described_class.process(args) } - expect(output).to eql("Draft _drafts/#{draft_to_publish} was published to _posts/#{post_filename}\n") + expect(output).to eql("Draft _drafts/#{draft_to_publish} was moved to _posts/#{post_filename}\n") end it 'publishes a draft on the specified date' do - path = Pathname.new(posts_dir).join "2012-03-04-a-test-post.md" + path = posts_dir.join "2012-03-04-a-test-post.md" capture_stdout { described_class.process(args, {"date" => '2012-3-4'}) } expect(path).to exist end @@ -49,7 +56,7 @@ it 'creates the posts folder if necessary' do FileUtils.rm_r posts_dir if File.directory? posts_dir capture_stdout { described_class.process(args) } - expect(Pathname.new(posts_dir)).to exist + expect(posts_dir).to exist end it 'errors if there is no argument' do diff --git a/spec/unpublish_spec.rb b/spec/unpublish_spec.rb new file mode 100644 index 0000000..cdffff3 --- /dev/null +++ b/spec/unpublish_spec.rb @@ -0,0 +1,60 @@ +RSpec.describe(Jekyll::Commands::Unpublish) do + let(:drafts_dir) { Pathname.new(source_dir('_drafts')) } + let(:posts_dir) { Pathname.new(source_dir('_posts')) } + let(:post_name) { "a-test-post.md" } + let(:post_filename) { "2012-03-04-#{post_name}" } + let(:post_path) { posts_dir.join post_filename } + let(:draft_path) { drafts_dir.join post_name } + + let(:args) { ["_posts/#{post_filename}"] } + + before(:all) do + FileUtils.mkdir_p source_dir unless File.directory? source_dir + Dir.chdir source_dir + end + + before(:each) do + FileUtils.mkdir_p drafts_dir unless File.directory? drafts_dir + FileUtils.mkdir_p posts_dir unless File.directory? posts_dir + FileUtils.touch post_path + end + + after(:each) do + FileUtils.rm_r drafts_dir if File.directory? drafts_dir + FileUtils.rm_r posts_dir if File.directory? posts_dir + end + + it 'moves a post back to _drafts' do + expect(post_path).to exist + expect(draft_path).not_to exist + capture_stdout { described_class.process(args) } + expect(post_path).not_to exist + expect(draft_path).to exist + end + + it 'writes a helpful message on success' do + expect(post_path).to exist + output = capture_stdout { described_class.process(args) } + expect(output).to eql("Post _posts/#{post_filename} was moved to _drafts/#{post_name}\n") + end + + it 'creates the drafts folder if necessary' do + FileUtils.rm_r drafts_dir if File.directory? drafts_dir + capture_stdout { described_class.process(args) } + expect(drafts_dir).to exist + end + + it 'errors if there is no argument' do + expect(-> { + capture_stdout { described_class.process } + }).to raise_error('You must specify a post path.') + end + + it 'errors if no file exists at given path' do + weird_path = '_posts/i-forgot-the-date.md' + expect(-> { + capture_stdout { described_class.process [weird_path] } + }).to raise_error("There was no post found at '#{weird_path}'.") + end + +end