diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..67ee52d --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,19 @@ +# TODO: Eval is required for the .homesickrc feature. This should eventually be +# removed if the feature is implemented in a more secure way. +Eval: + Enabled: false + +# TODO: The following settings disable reports about issues that can be fixed +# through refactoring. Remove these as offenses are removed from the code base. + +ClassLength: + Enabled: false + +CyclomaticComplexity: + Max: 13 + +LineLength: + Enabled: false + +MethodLength: + Max: 36 diff --git a/lib/homesick.rb b/lib/homesick.rb index 6ebd0cc..5f32e64 100644 --- a/lib/homesick.rb +++ b/lib/homesick.rb @@ -1,6 +1,7 @@ # -*- encoding : utf-8 -*- require 'thor' +# Homesick's command line interface (with some helper methods) class Homesick < Thor autoload :Shell, 'homesick/shell' autoload :Actions, 'homesick/actions' @@ -33,34 +34,23 @@ class Homesick < Thor destination = nil if File.exist?(uri) uri = Pathname.new(uri).expand_path - if uri.to_s.start_with?(repos_dir.to_s) - raise "Castle already cloned to #{uri}" - end + fail "Castle already cloned to #{uri}" if uri.to_s.start_with?(repos_dir.to_s) destination = uri.basename ln_s uri, destination elsif uri =~ GITHUB_NAME_REPO_PATTERN destination = Pathname.new(uri).basename - git_clone "https://github.com/#{$1}.git", :destination => destination - elsif uri =~ /%r([^%r]*?)(\.git)?\Z/ - destination = Pathname.new($1) - git_clone uri - elsif uri =~ /[^:]+:([^:]+)(\.git)?\Z/ - destination = Pathname.new($1) + git_clone "https://github.com/#{Regexp.last_match[1]}.git", + destination: destination + elsif uri =~ /%r([^%r]*?)(\.git)?\Z/ || uri =~ /[^:]+:([^:]+)(\.git)?\Z/ + destination = Pathname.new(Regexp.last_match[1]) git_clone uri else - raise "Unknown URI format: #{uri}" + fail "Unknown URI format: #{uri}" end - if destination.join('.gitmodules').exist? - inside destination do - git_submodule_init - git_submodule_update - end - end - - rc(destination) + setup_castle(destination) end end @@ -77,14 +67,20 @@ class Homesick < Thor eval homesickrc.read, binding, homesickrc.expand_path.to_s end else - shell.say_status 'eval skip', "not evaling #{homesickrc}, #{destination} may need manual configuration", :blue + shell.say_status 'eval skip', + "not evaling #{homesickrc}, #{destination} may need manual configuration", + :blue end end end end desc 'pull CASTLE', 'Update the specified castle' - method_option :all, :type => :boolean, :default => false, :required => false, :desc => 'Update all cloned castles' + method_option :all, + type: :boolean, + default: false, + required: false, + desc: 'Update all cloned castles' def pull(name = DEFAULT_CASTLE_NAME) if options[:all] inside_each_castle do |castle| @@ -94,13 +90,11 @@ class Homesick < Thor else update_castle name end - end desc 'commit CASTLE MESSAGE', "Commit the specified castle's changes" def commit(name = DEFAULT_CASTLE_NAME, message = nil) commit_castle name, message - end desc 'push CASTLE', 'Push the specified castle' @@ -126,7 +120,9 @@ class Homesick < Thor end desc 'link CASTLE', 'Symlinks all dotfiles from the specified castle' - method_option :force, :default => false, :desc => 'Overwrite existing conflicting symlinks without prompting.' + method_option :force, + default: false, + desc: 'Overwrite existing conflicting symlinks without prompting.' def link(name = DEFAULT_CASTLE_NAME) check_castle_existance(name, 'symlink') @@ -166,7 +162,9 @@ class Homesick < Thor target.delete mv absolute_path, castle_path else - shell.say_status(:track, "#{target} already exists, and is more recent than #{file}. Run 'homesick SYMLINK CASTLE' to create symlinks.", :blue) unless options[:quiet] + shell.say_status(:track, + "#{target} already exists, and is more recent than #{file}. Run 'homesick SYMLINK CASTLE' to create symlinks.", + :blue) unless options[:quiet] end else mv absolute_path, castle_path @@ -189,7 +187,9 @@ class Homesick < Thor desc 'list', 'List cloned castles' def list inside_each_castle do |castle| - say_status castle.relative_path_from(repos_dir).to_s, `git config remote.origin.url`.chomp, :cyan + say_status castle.relative_path_from(repos_dir).to_s, + `git config remote.origin.url`.chomp, + :cyan end end @@ -235,37 +235,43 @@ class Homesick < Thor end end - desc "destroy CASTLE", "Delete all symlinks and remove the cloned repository" + desc 'destroy CASTLE', 'Delete all symlinks and remove the cloned repository' def destroy(name) - check_castle_existance name, "destroy" + check_castle_existance name, 'destroy' - if shell.yes?("This will destroy your castle irreversible! Are you sure?") + if shell.yes?('This will destroy your castle irreversible! Are you sure?') unlink(name) rm_rf repos_dir.join(name) end - end - desc "cd CASTLE", "Open a new shell in the root of the given castle" + desc 'cd CASTLE', 'Open a new shell in the root of the given castle' def cd(castle = DEFAULT_CASTLE_NAME) - check_castle_existance castle, "cd" + check_castle_existance castle, 'cd' castle_dir = repos_dir.join(castle) - say_status "cd #{castle_dir.realpath}", "Opening a new shell in castle '#{castle}'. To return to the original one exit from the new shell.", :green + say_status "cd #{castle_dir.realpath}", + "Opening a new shell in castle '#{castle}'. To return to the original one exit from the new shell.", + :green inside castle_dir do system(ENV['SHELL']) end end - desc "open CASTLE", "Open your default editor in the root of the given castle" + desc 'open CASTLE', + 'Open your default editor in the root of the given castle' def open(castle = DEFAULT_CASTLE_NAME) - if ! ENV['EDITOR'] - say_status :error,"The $EDITOR environment variable must be set to use this command", :red + unless ENV['EDITOR'] + say_status :error, + 'The $EDITOR environment variable must be set to use this command', + :red exit(1) end - check_castle_existance castle, "open" + check_castle_existance castle, 'open' castle_dir = repos_dir.join(castle) - say_status "#{ENV['EDITOR']} #{castle_dir.realpath}", "Opening the root directory of castle '#{castle}' in editor '#{ENV['EDITOR']}'.", :green + say_status "#{ENV['EDITOR']} #{castle_dir.realpath}", + "Opening the root directory of castle '#{castle}' in editor '#{ENV['EDITOR']}'.", + :green inside castle_dir do system(ENV['EDITOR']) end @@ -292,7 +298,9 @@ class Homesick < Thor def check_castle_existance(name, action) unless castle_dir(name).exist? - say_status :error, "Could not #{action} #{name}, expected #{castle_dir(name)} exist and contain dotfiles", :red + say_status :error, + "Could not #{action} #{name}, expected #{castle_dir(name)} exist and contain dotfiles", + :red exit(1) end @@ -301,7 +309,7 @@ class Homesick < Thor def all_castles dirs = Pathname.glob("#{repos_dir}/**/.git", File::FNM_DOTMATCH) # reject paths that lie inside another castle, like git submodules - return dirs.reject do |dir| + dirs.reject do |dir| dirs.any? do |other| dir != other && dir.fnmatch(other.parent.join('*').to_s) end @@ -329,7 +337,7 @@ class Homesick < Thor def commit_castle(castle, message) check_castle_existance(castle, 'commit') inside repos_dir.join(castle) do - git_commit_all :message => message + git_commit_all message: message end end @@ -371,7 +379,9 @@ class Homesick < Thor def subdir_remove(castle, path) subdir_filepath = subdir_file(castle) if subdir_filepath.exist? - lines = IO.readlines(subdir_filepath).delete_if { |line| line == "#{path}\n" } + lines = IO.readlines(subdir_filepath).delete_if do |line| + line == "#{path}\n" + end File.open(subdir_filepath, 'w') { |manfile| manfile.puts lines } end @@ -403,10 +413,16 @@ class Homesick < Thor first_p.mtime > second_p.mtime && !first_p.symlink? end + def collision_accepted? + options[:force] || shell.file_collision(destination) { source } + end + def each_file(castle, basedir, subdirs) absolute_basedir = Pathname.new(basedir).expand_path inside basedir do - files = Pathname.glob('{.*,*}').reject{ |a| ['.', '..'].include?(a.to_s) } + files = Pathname.glob('{.*,*}').reject do |a| + ['.', '..'].include?(a.to_s) + end files.each do |path| absolute_path = path.expand_path castle_home = castle_dir(castle) @@ -434,7 +450,7 @@ class Homesick < Thor home_path = home_dir.join(relative_dir).join(path) yield(absolute_path, home_path) - end + end end end @@ -449,4 +465,15 @@ class Homesick < Thor ln_s absolute_path, home_path end end + + def setup_castle(path) + if path.join('.gitmodules').exist? + inside path do + git_submodule_init + git_submodule_update + end + end + + rc(path) + end end diff --git a/lib/homesick/actions.rb b/lib/homesick/actions.rb index 5c603f0..ef6600d 100644 --- a/lib/homesick/actions.rb +++ b/lib/homesick/actions.rb @@ -1,7 +1,8 @@ # -*- encoding : utf-8 -*- class Homesick + # Git-related and file-related helper methods for the Homesick class module Actions - # TODO move this to be more like thor's template, empty_directory, etc + # TODO: move this to be more like thor's template, empty_directory, etc def git_clone(repo, config = {}) config ||= {} destination = config[:destination] || File.basename(repo, '.git') @@ -9,11 +10,13 @@ class Homesick destination = Pathname.new(destination) unless destination.kind_of?(Pathname) FileUtils.mkdir_p destination.dirname - if ! destination.directory? - say_status 'git clone', "#{repo} to #{destination.expand_path}", :green unless options[:quiet] - system "git clone -q --config push.default=upstream --recursive #{repo} #{destination}" unless options[:pretend] - else + if destination.directory? say_status :exist, destination.expand_path, :blue unless options[:quiet] + else + say_status 'git clone', + "#{repo} to #{destination.expand_path}", + :green unless options[:quiet] + system "git clone -q --config push.default=upstream --recursive #{repo} #{destination}" unless options[:pretend] end end @@ -21,11 +24,11 @@ class Homesick path = Pathname.new(path) inside path do - if !path.join('.git').exist? + if path.join('.git').exist? + say_status 'git init', 'already initialized', :blue unless options[:quiet] + else say_status 'git init', '' unless options[:quiet] system 'git init >/dev/null' unless options[:pretend] - else - say_status 'git init', 'already initialized', :blue unless options[:quiet] end end end @@ -34,11 +37,11 @@ class Homesick existing_remote = `git config remote.#{name}.url`.chomp existing_remote = nil if existing_remote == '' - if !existing_remote + if existing_remote + say_status 'git remote', "#{name} already exists", :blue unless options[:quiet] + else say_status 'git remote', "add #{name} #{url}" unless options[:quiet] system "git remote add #{name} #{url}" unless options[:pretend] - else - say_status 'git remote', "#{name} already exists", :blue unless options[:quiet] end end @@ -78,12 +81,12 @@ class Homesick def git_status(config = {}) say_status 'git status', '', :green unless options[:quiet] - system "git status" unless options[:pretend] + system 'git status' unless options[:pretend] end def git_diff(config = {}) say_status 'git diff', '', :green unless options[:quiet] - system "git diff" unless options[:pretend] + system 'git diff' unless options[:pretend] end def mv(source, destination, config = {}) @@ -93,9 +96,7 @@ class Homesick if destination.exist? say_status :conflict, "#{destination} exists", :red unless options[:quiet] - if options[:force] || shell.file_collision(destination) { source } - system "mv '#{source}' '#{destination}'" unless options[:pretend] - end + system "mv '#{source}' '#{destination}'" if (options[:force] || shell.file_collision(destination) { source }) && !options[:pretend] else # this needs some sort of message here. system "mv '#{source}' '#{destination}'" unless options[:pretend] @@ -133,25 +134,40 @@ class Homesick destination = Pathname.new(destination) FileUtils.mkdir_p destination.dirname - if destination.symlink? - if destination.readlink == source - say_status :identical, destination.expand_path, :blue unless options[:quiet] - else - say_status :conflict, "#{destination} exists and points to #{destination.readlink}", :red unless options[:quiet] + action = if destination.symlink? && destination.readlink == source + :identical + elsif destination.symlink? + :symlink_conflict + elsif destination.exist? + :conflict + else + :success + end - if options[:force] || shell.file_collision(destination) { source } - system "ln -nsf '#{source}' '#{destination}'" unless options[:pretend] - end - end - elsif destination.exist? + handle_symlink_action action, source, destination + end + + def handle_symlink_action(action, source, destination) + case action + when :identical + say_status :identical, destination.expand_path, :blue unless options[:quiet] + when :symlink_conflict + say_status :conflict, + "#{destination} exists and points to #{destination.readlink}", + :red unless options[:quiet] + + system "ln -nsf '#{source}' '#{destination}'" if collision_accepted? + when :conflict say_status :conflict, "#{destination} exists", :red unless options[:quiet] - if options[:force] || shell.file_collision(destination) { source } + if collision_accepted? system "rm -rf '#{destination}'" unless options[:pretend] system "ln -sf '#{source}' '#{destination}'" unless options[:pretend] end else - say_status :symlink, "#{source.expand_path} to #{destination.expand_path}", :green unless options[:quiet] + say_status :symlink, + "#{source.expand_path} to #{destination.expand_path}", + :green unless options[:quiet] system "ln -s '#{source}' '#{destination}'" unless options[:pretend] end end diff --git a/lib/homesick/shell.rb b/lib/homesick/shell.rb index 880801c..7bf1a65 100644 --- a/lib/homesick/shell.rb +++ b/lib/homesick/shell.rb @@ -1,7 +1,6 @@ class Homesick # Hack in support for diffing symlinks class Shell < Thor::Shell::Color - def show_diff(destination, content) destination = Pathname.new(destination) @@ -12,6 +11,5 @@ class Homesick super end end - end end diff --git a/lib/homesick/version.rb b/lib/homesick/version.rb index a81902d..5c5dfcb 100644 --- a/lib/homesick/version.rb +++ b/lib/homesick/version.rb @@ -1,5 +1,7 @@ # -*- encoding : utf-8 -*- class Homesick + # A representation of Homesick's version number in constants, including a + # String of the entire version number module Version MAJOR = 1 MINOR = 0 diff --git a/spec/homesick_spec.rb b/spec/homesick_spec.rb index 2078998..a2ac4e9 100644 --- a/spec/homesick_spec.rb +++ b/spec/homesick_spec.rb @@ -18,7 +18,9 @@ describe 'homesick' do somewhere = create_construct local_repo = somewhere.directory('some_repo') local_repo.file('.homesickrc') do |file| - file << "File.open(Dir.pwd + '/testing', 'w') { |f| f.print 'testing' }" + file << "File.open(Dir.pwd + '/testing', 'w') do |f| + f.print 'testing' + end" end expect($stdout).to receive(:print) @@ -56,33 +58,39 @@ describe 'homesick' do it 'should clone git repo like file:///path/to.git' do bare_repo = File.join(create_construct.to_s, 'dotfiles.git') system "git init --bare #{bare_repo} >/dev/null 2>&1" + # Capture stderr to suppress message about cloning an empty repo. Capture.stderr do homesick.clone "file://#{bare_repo}" end - File.directory?(File.join(home.to_s, '.homesick/repos/dotfiles')).should be_true + File.directory?(File.join(home.to_s, '.homesick/repos/dotfiles')) + .should be_true end it 'should clone git repo like git://host/path/to.git' do - homesick.should_receive(:git_clone).with('git://github.com/technicalpickles/pickled-vim.git') + homesick.should_receive(:git_clone) + .with('git://github.com/technicalpickles/pickled-vim.git') homesick.clone 'git://github.com/technicalpickles/pickled-vim.git' end it 'should clone git repo like git@host:path/to.git' do - homesick.should_receive(:git_clone).with('git@github.com:technicalpickles/pickled-vim.git') + homesick.should_receive(:git_clone) + .with('git@github.com:technicalpickles/pickled-vim.git') homesick.clone 'git@github.com:technicalpickles/pickled-vim.git' end it 'should clone git repo like http://host/path/to.git' do - homesick.should_receive(:git_clone).with('http://github.com/technicalpickles/pickled-vim.git') + homesick.should_receive(:git_clone) + .with('http://github.com/technicalpickles/pickled-vim.git') homesick.clone 'http://github.com/technicalpickles/pickled-vim.git' end it 'should clone git repo like http://host/path/to' do - homesick.should_receive(:git_clone).with('http://github.com/technicalpickles/pickled-vim') + homesick.should_receive(:git_clone) + .with('http://github.com/technicalpickles/pickled-vim') homesick.clone 'http://github.com/technicalpickles/pickled-vim' end @@ -99,7 +107,9 @@ describe 'homesick' do end it 'should clone a github repo' do - homesick.should_receive(:git_clone).with('https://github.com/wfarr/dotfiles.git', :destination => Pathname.new('dotfiles')) + homesick.should_receive(:git_clone) + .with('https://github.com/wfarr/dotfiles.git', + destination: Pathname.new('dotfiles')) homesick.clone 'wfarr/dotfiles' end @@ -116,7 +126,9 @@ describe 'homesick' do it 'executes the .homesickrc' do castle.file('.homesickrc') do |file| - file << "File.open(Dir.pwd + '/testing', 'w') { |f| f.print 'testing' }" + file << "File.open(Dir.pwd + '/testing', 'w') do |f| + f.print 'testing' + end" end expect_any_instance_of(Thor::Shell::Basic).to receive(:say_status).with('eval', kind_of(Pathname)) @@ -134,7 +146,9 @@ describe 'homesick' do it 'does not execute the .homesickrc' do castle.file('.homesickrc') do |file| - file << "File.open(Dir.pwd + '/testing', 'w') { |f| f.print 'testing' }" + file << "File.open(Dir.pwd + '/testing', 'w') do |f| + f.print 'testing' + end" end expect_any_instance_of(Thor::Shell::Basic).to receive(:say_status).with('eval skip', /not evaling.+/, :blue) @@ -165,7 +179,7 @@ describe 'homesick' do end context 'when forced' do - let(:homesick) { Homesick.new [], :force => true } + let(:homesick) { Homesick.new [], force: true } it 'can override symlinks to directories' do somewhere_else = create_construct @@ -219,7 +233,9 @@ describe 'homesick' do end context "with '.config' and '.config/someapp' in .homesick_subdir" do - let(:castle) { given_castle('glencairn', ['.config', '.config/someapp']) } + let(:castle) do + given_castle('glencairn', ['.config', '.config/someapp']) + end it 'can symlink under both of .config and .config/someapp' do config_dir = castle.directory('.config') config_dotfile = config_dir.file('.some_dotfile') @@ -231,13 +247,15 @@ describe 'homesick' do home_config_dir = home.join('.config') home_someapp_dir = home_config_dir.join('someapp') home_config_dir.symlink?.should be == false - home_config_dir.join('.some_dotfile').readlink.should be == config_dotfile + home_config_dir.join('.some_dotfile').readlink + .should be == config_dotfile home_someapp_dir.symlink?.should be == false - home_someapp_dir.join('.some_appfile').readlink.should == someapp_dotfile + home_someapp_dir.join('.some_appfile').readlink + .should == someapp_dotfile end end - context "when call with no castle name" do + context 'when call with no castle name' do let(:castle) { given_castle('dotfiles') } it 'using default castle name: "dotfiles"' do dotfile = castle.file('.some_dotfile') @@ -301,7 +319,9 @@ describe 'homesick' do end context "with '.config' and '.config/someapp' in .homesick_subdir" do - let(:castle) { given_castle('glencairn', ['.config', '.config/someapp']) } + let(:castle) do + given_castle('glencairn', ['.config', '.config/someapp']) + end it 'can unsymlink under both of .config and .config/someapp' do config_dir = castle.directory('.config') @@ -320,7 +340,7 @@ describe 'homesick' do end end - context "when call with no castle name" do + context 'when call with no castle name' do let(:castle) { given_castle('dotfiles') } it 'using default castle name: "dotfiles"' do @@ -339,8 +359,14 @@ describe 'homesick' do given_castle('zomg') given_castle('wtf/zomg') - homesick.should_receive(:say_status).with('zomg', 'git://github.com/technicalpickles/zomg.git', :cyan) - homesick.should_receive(:say_status).with('wtf/zomg', 'git://github.com/technicalpickles/zomg.git', :cyan) + homesick.should_receive(:say_status) + .with('zomg', + 'git://github.com/technicalpickles/zomg.git', + :cyan) + homesick.should_receive(:say_status) + .with('wtf/zomg', + 'git://github.com/technicalpickles/zomg.git', + :cyan) homesick.list end @@ -358,7 +384,8 @@ describe 'homesick' do some_rc_file = home.file '.some_rc_file' homesick.track(some_rc_file.to_s, 'castle_repo') text = Capture.stdout { homesick.status('castle_repo') } - text.should =~ /Changes to be committed:.*new file:\s*home\/.some_rc_file/m + text.should =~ + /Changes to be committed:.*new file:\s*home\/.some_rc_file/m end end @@ -367,7 +394,9 @@ describe 'homesick' do given_castle('castle_repo') some_rc_file = home.file '.some_rc_file' homesick.track(some_rc_file.to_s, 'castle_repo') - Capture.stdout { homesick.commit 'castle_repo', 'Adding a file to the test' } + Capture.stdout do + homesick.commit 'castle_repo', 'Adding a file to the test' + end text = Capture.stdout { homesick.diff('castle_repo') } text.should eq('') end @@ -376,9 +405,11 @@ describe 'homesick' do given_castle('castle_repo') some_rc_file = home.file '.some_rc_file' homesick.track(some_rc_file.to_s, 'castle_repo') - Capture.stdout { homesick.commit 'castle_repo', 'Adding a file to the test' } + Capture.stdout do + homesick.commit 'castle_repo', 'Adding a file to the test' + end File.open(some_rc_file.to_s, 'w') do |file| - file.puts "Some test text" + file.puts 'Some test text' end text = Capture.stdout { homesick.diff('castle_repo') } text.should =~ /diff --git.+Some test text$/m @@ -405,8 +436,11 @@ describe 'homesick' do end it 'should print an error message when trying to pull a non-existant castle' do - homesick.should_receive("say_status").once.with(:error, /Could not pull castle_repo, expected \/tmp\/construct_container.* exist and contain dotfiles/, :red) - expect { homesick.pull "castle_repo" }.to raise_error(SystemExit) + homesick.should_receive('say_status').once + .with(:error, + %r{Could not pull castle_repo, expected /tmp/construct_container.* exist and contain dotfiles}, + :red) + expect { homesick.pull 'castle_repo' }.to raise_error(SystemExit) end describe '--all' do @@ -414,9 +448,13 @@ describe 'homesick' do given_castle('castle_repo') given_castle('glencairn') homesick.stub(:system).exactly(2).times.with('git pull --quiet') - homesick.stub(:system).exactly(2).times.with('git submodule --quiet init') - homesick.stub(:system).exactly(2).times.with('git submodule --quiet update --init --recursive >/dev/null 2>&1') - Capture.stdout { Capture.stderr { homesick.invoke 'pull', [], all: true } } + homesick.stub(:system).exactly(2).times + .with('git submodule --quiet init') + homesick.stub(:system).exactly(2).times + .with('git submodule --quiet update --init --recursive >/dev/null 2>&1') + Capture.stdout do + Capture.stderr { homesick.invoke 'pull', [], all: true } + end end end @@ -430,8 +468,11 @@ describe 'homesick' do end it 'should print an error message when trying to push a non-existant castle' do - homesick.should_receive("say_status").once.with(:error, /Could not push castle_repo, expected \/tmp\/construct_container.* exist and contain dotfiles/, :red) - expect { homesick.push "castle_repo" }.to raise_error(SystemExit) + homesick.should_receive('say_status').once + .with(:error, + %r{Could not push castle_repo, expected /tmp/construct_container.* exist and contain dotfiles}, + :red) + expect { homesick.push 'castle_repo' }.to raise_error(SystemExit) end end @@ -484,7 +525,7 @@ describe 'homesick' do some_nested_dir.realpath.should == tracked_file.realpath end - context "when call with no castle name" do + context 'when call with no castle name' do it 'using default castle name: "dotfiles"' do castle = given_castle('dotfiles') @@ -504,11 +545,15 @@ describe 'homesick' do given_castle('castle_repo') some_rc_file = home.file '.a_random_rc_file' homesick.track(some_rc_file.to_s, 'castle_repo') - text = Capture.stdout { homesick.commit('castle_repo', 'Test message') } + text = Capture.stdout do + homesick.commit('castle_repo', 'Test message') + end text.should =~ /^\[master \(root-commit\) \w+\] Test message/ end end + # Note that this is a test for the subdir_file related feature of track, + # not for the subdir_file method itself. describe 'subdir_file' do it 'should add the nested files parent to the subdir_file' do @@ -553,62 +598,75 @@ describe 'homesick' do end end - describe "destroy" do - it "removes the symlink files" do + describe 'destroy' do + it 'removes the symlink files' do expect_any_instance_of(Thor::Shell::Basic).to receive(:yes?).and_return('y') - given_castle("stronghold") + given_castle('stronghold') some_rc_file = home.file '.some_rc_file' - homesick.track(some_rc_file.to_s, "stronghold") + homesick.track(some_rc_file.to_s, 'stronghold') homesick.destroy('stronghold') some_rc_file.should_not be_exist end - it "deletes the cloned repository" do + it 'deletes the cloned repository' do expect_any_instance_of(Thor::Shell::Basic).to receive(:yes?).and_return('y') - castle = given_castle("stronghold") + castle = given_castle('stronghold') some_rc_file = home.file '.some_rc_file' - homesick.track(some_rc_file.to_s, "stronghold") + homesick.track(some_rc_file.to_s, 'stronghold') homesick.destroy('stronghold') castle.should_not be_exist end end - describe "cd" do + describe 'cd' do it "cd's to the root directory of the given castle" do given_castle('castle_repo') - homesick.should_receive("inside").once.with(kind_of(Pathname)).and_yield - homesick.should_receive("system").once.with(ENV["SHELL"]) + homesick.should_receive('inside').once.with(kind_of(Pathname)).and_yield + homesick.should_receive('system').once.with(ENV['SHELL']) Capture.stdout { homesick.cd 'castle_repo' } end - it "returns an error message when the given castle does not exist" do - homesick.should_receive("say_status").once.with(:error, /Could not cd castle_repo, expected \/tmp\/construct_container.* exist and contain dotfiles/, :red) - expect { homesick.cd "castle_repo" }.to raise_error(SystemExit) + it 'returns an error message when the given castle does not exist' do + homesick.should_receive('say_status').once + .with(:error, + %r{Could not cd castle_repo, expected /tmp/construct_container.* exist and contain dotfiles}, + :red) + expect { homesick.cd 'castle_repo' }.to raise_error(SystemExit) end end - describe "open" do - it "opens the system default editor in the root of the given castle" do - ENV.stub(:[]).and_call_original # Make sure calls to ENV use default values for most things... - ENV.stub(:[]).with('EDITOR').and_return('vim') # Set a default value for 'EDITOR' just in case none is set + describe 'open' do + it 'opens the system default editor in the root of the given castle' do + # Make sure calls to ENV use default values for most things... + ENV.stub(:[]).and_call_original + # Set a default value for 'EDITOR' just in case none is set + ENV.stub(:[]).with('EDITOR').and_return('vim') given_castle 'castle_repo' - homesick.should_receive("inside").once.with(kind_of(Pathname)).and_yield - homesick.should_receive("system").once.with('vim') + homesick.should_receive('inside').once.with(kind_of(Pathname)).and_yield + homesick.should_receive('system').once.with('vim') Capture.stdout { homesick.open 'castle_repo' } end - it "returns an error message when the $EDITOR environment variable is not set" do - ENV.stub(:[]).with('EDITOR').and_return(nil) # Set the default editor to make sure it fails. - homesick.should_receive("say_status").once.with(:error, "The $EDITOR environment variable must be set to use this command", :red) - expect { homesick.open "castle_repo" }.to raise_error(SystemExit) + it 'returns an error message when the $EDITOR environment variable is not set' do + # Set the default editor to make sure it fails. + ENV.stub(:[]).with('EDITOR').and_return(nil) + homesick.should_receive('say_status').once + .with(:error, + 'The $EDITOR environment variable must be set to use this command', + :red) + expect { homesick.open 'castle_repo' }.to raise_error(SystemExit) end - it "returns an error message when the given castle does not exist" do - ENV.stub(:[]).with('EDITOR').and_return('vim') # Set a default just in case none is set - homesick.should_receive("say_status").once.with(:error, /Could not open castle_repo, expected \/tmp\/construct_container.* exist and contain dotfiles/, :red) - expect { homesick.open "castle_repo" }.to raise_error(SystemExit) + it 'returns an error message when the given castle does not exist' do + # Set a default just in case none is set + ENV.stub(:[]).with('EDITOR').and_return('vim') + homesick.should_receive('say_status').once + .with(:error, + %r{Could not open castle_repo, expected /tmp/construct_container.* exist and contain dotfiles}, + :red) + expect { homesick.open 'castle_repo' }.to raise_error(SystemExit) end end