From 7f0af24ada6390b96d41bc8326983d26762bf7af Mon Sep 17 00:00:00 2001 From: Claudio Bley Date: Tue, 22 Dec 2020 14:33:53 +0100 Subject: [PATCH] Use rubocop's default include configuration and fix all offenses --- .rubocop.yml | 5 - Gemfile | 2 + colorls.gemspec | 6 +- spec/color_ls/core_spec.rb | 71 ++++---- spec/color_ls/flags_spec.rb | 269 ++++++++++++++++-------------- spec/color_ls/git_spec.rb | 12 +- spec/color_ls/layout_spec.rb | 2 + spec/color_ls/monkey_spec.rb | 8 +- spec/color_ls/yaml_spec.rb | 8 +- spec/color_ls_spec.rb | 2 + spec/spec_helper.rb | 4 +- spec/support/yaml_sort_checker.rb | 2 + 12 files changed, 215 insertions(+), 176 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index a477a8c..fb44f6d 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -3,15 +3,10 @@ require: - rubocop-rake AllCops: - Include: - - 'lib/**/*' - - 'Rakefile' Exclude: - 'vendor/**/*' - 'benchmarks/*' - 'profile/*' - - 'lib/yaml/*' - - 'lib/**/*.sh' DisplayCopNames: true NewCops: enable TargetRubyVersion: 2.5 diff --git a/Gemfile b/Gemfile index fa75df1..7f4f5e9 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,5 @@ +# frozen_string_literal: true + source 'https://rubygems.org' gemspec diff --git a/colorls.gemspec b/colorls.gemspec index 95c3b55..924ae8e 100644 --- a/colorls.gemspec +++ b/colorls.gemspec @@ -1,3 +1,5 @@ +# frozen_string_literal: true + lib = File.expand_path('lib', __dir__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'colorls/version' @@ -21,7 +23,7 @@ POST_INSTALL_MESSAGE = %( Man pages have been added. Checkout `man colorls`. ******************************************************************* -).freeze +) # rubocop:disable Metrics/BlockLength Gem::Specification.new do |spec| @@ -47,7 +49,7 @@ Gem::Specification.new do |spec| spec.required_ruby_version = '>= 2.5.0' - spec.files = IO.popen( + spec.files = IO.popen( %w[git ls-files -z], external_encoding: Encoding::ASCII_8BIT ).read.split("\x0").reject do |f| f.match(%r{^(test|spec|features)/}) diff --git a/spec/color_ls/core_spec.rb b/spec/color_ls/core_spec.rb index 86cd27b..2ba175a 100644 --- a/spec/color_ls/core_spec.rb +++ b/spec/color_ls/core_spec.rb @@ -1,4 +1,5 @@ -# coding: utf-8 +# frozen_string_literal: false + require 'spec_helper' RSpec.describe ColorLS::Core do @@ -6,59 +7,59 @@ RSpec.describe ColorLS::Core do context 'ls' do it 'works with Unicode characters' do - camera = 'Cámara'.force_encoding(ColorLS::file_encoding) - imagenes = 'Imágenes'.force_encoding(ColorLS::file_encoding) + camera = 'Cámara'.force_encoding(ColorLS.file_encoding) + imagenes = 'Imágenes'.force_encoding(ColorLS.file_encoding) - dirInfo = instance_double( + dir_info = instance_double( 'FileInfo', - :group => "sys", - :mtime => Time.now, - :directory? => true, - :owner => "user", - :name => imagenes, - :show => imagenes, - :nlink => 1, - :size => 128, - :blockdev? => false, - :chardev? => false, - :socket? => false, - :symlink? => false, - :stats => OpenStruct.new( + group: 'sys', + mtime: Time.now, + directory?: true, + owner: 'user', + name: imagenes, + show: imagenes, + nlink: 1, + size: 128, + blockdev?: false, + chardev?: false, + socket?: false, + symlink?: false, + stats: OpenStruct.new( mode: 0o444, # read for user, owner, other setuid?: false, setgid?: false, sticky?: false ), - :executable? => true + executable?: true ) - fileInfo = instance_double( + file_info = instance_double( 'FileInfo', - :group => "sys", - :mtime => Time.now, - :directory? => false, - :owner => "user", - :name => camera, - :show => camera, - :nlink => 1, - :size => 128, - :blockdev? => false, - :chardev? => false, - :socket? => false, - :symlink? => false, - :stats => OpenStruct.new( + group: 'sys', + mtime: Time.now, + directory?: false, + owner: 'user', + name: camera, + show: camera, + nlink: 1, + size: 128, + blockdev?: false, + chardev?: false, + socket?: false, + symlink?: false, + stats: OpenStruct.new( mode: 0o444, # read for user, owner, other setuid?: false, setgid?: false, sticky?: false ), - :executable? => false + executable?: false ) expect(::Dir).to receive(:entries).and_return([camera]) - allow(ColorLS::FileInfo).to receive(:new).and_return(dirInfo) - allow(ColorLS::FileInfo).to receive(:new).with(File.join(imagenes, camera), link_info: false) { fileInfo } + allow(ColorLS::FileInfo).to receive(:new).and_return(dir_info) + allow(ColorLS::FileInfo).to receive(:new).with(File.join(imagenes, camera), link_info: false) { file_info } expect { subject.ls('Imágenes') }.to output(/mara/).to_stdout end diff --git a/spec/color_ls/flags_spec.rb b/spec/color_ls/flags_spec.rb index 2932543..06d58cd 100644 --- a/spec/color_ls/flags_spec.rb +++ b/spec/color_ls/flags_spec.rb @@ -1,27 +1,30 @@ -# coding: utf-8 +# frozen_string_literal: true + require 'spec_helper' -RSpec.describe ColorLS::Flags do - FIXTURES = 'spec/fixtures'.freeze +FIXTURES = 'spec/fixtures' +RSpec.describe ColorLS::Flags do subject do - begin - described_class.new(*args).process - rescue SystemExit => e - raise "colorls exited with #{e.status}" unless e.success? - end + described_class.new(*args).process + rescue SystemExit => e + raise "colorls exited with #{e.status}" unless e.success? end context 'with no flags' do let(:args) { [FIXTURES] } - it('does not list file info') { expect { subject }.not_to output(/((r|-).*(w|-).*(x|-).*){3}/).to_stdout } + it('does not list file info') { + expect do + subject + end.not_to output(/((r|-).*(w|-).*(x|-).*){3}/).to_stdout + } it('does not display hidden files') { expect { subject }.not_to output(/\.hidden-file/).to_stdout } it('does not show a report') { expect { subject }.not_to output(/Found \d+ contents/).to_stdout } it('displays dirs & files alphabetically') { expect { subject }.to output(/a-file.+symlinks.+z-file/m).to_stdout } it 'displays multiple files per line' do - expect(::STDOUT).to receive(:tty?).and_return(true) + expect($stdout).to receive(:tty?).and_return(true) expect { subject }.not_to output(/(.*\n){3}/).to_stdout end @@ -33,16 +36,22 @@ RSpec.describe ColorLS::Flags do context 'with --reverse flag' do let(:args) { ['--reverse', '-x', FIXTURES] } - it('displays dirs & files in reverse alphabetical order') { expect { subject }.to output(/z-file.+symlinks.+a-file/m).to_stdout } + it('displays dirs & files in reverse alphabetical order') { + expect do + subject + end.to output(/z-file.+symlinks.+a-file/m).to_stdout + } end context 'with --format flag' do let(:args) { ['--format=single-column', FIXTURES] } - it { expect { subject }.to output(/.*a-file.*\n # on the first line + it { + expect { subject }.to output(/.*a-file.*\n # on the first line (?m:.*) # more lines... .*z-file.*\n # on the last line - /x).to_stdout } + /x).to_stdout + } end context 'with --long flag & file path' do @@ -61,59 +70,59 @@ RSpec.describe ColorLS::Flags do let(:args) { ['--long', "#{FIXTURES}/a.txt"] } it 'shows special permission bits' do - fileInfo = instance_double( + file_info = instance_double( 'FileInfo', - :group => "sys", - :mtime => Time.now, - :directory? => false, - :owner => "user", - :name => "a.txt", - :show => "a.txt", - :nlink => 1, - :size => 128, - :blockdev? => false, - :chardev? => false, - :socket? => false, - :symlink? => false, - :stats => OpenStruct.new( + group: 'sys', + mtime: Time.now, + directory?: false, + owner: 'user', + name: 'a.txt', + show: 'a.txt', + nlink: 1, + size: 128, + blockdev?: false, + chardev?: false, + socket?: false, + symlink?: false, + stats: OpenStruct.new( mode: 0o444, # read for user, owner, other setuid?: true, setgid?: true, sticky?: true ), - :executable? => false + executable?: false ) - allow(ColorLS::FileInfo).to receive(:new).with("#{FIXTURES}/a.txt", link_info: true) { fileInfo } + allow(ColorLS::FileInfo).to receive(:new).with("#{FIXTURES}/a.txt", link_info: true) { file_info } expect { subject }.to output(/r-Sr-Sr-T .* a.txt/mx).to_stdout end it 'shows number of hardlinks' do - fileInfo = instance_double( + file_info = instance_double( 'FileInfo', - :group => "sys", - :mtime => Time.now, - :directory? => false, - :owner => "user", - :name => "a.txt", - :show => "a.txt", - :nlink => 5, # number of hardlinks - :size => 128, - :blockdev? => false, - :chardev? => false, - :socket? => false, - :symlink? => false, - :stats => OpenStruct.new( + group: 'sys', + mtime: Time.now, + directory?: false, + owner: 'user', + name: 'a.txt', + show: 'a.txt', + nlink: 5, # number of hardlinks + size: 128, + blockdev?: false, + chardev?: false, + socket?: false, + symlink?: false, + stats: OpenStruct.new( mode: 0o444, # read for user, owner, other setuid?: true, setgid?: true, sticky?: true ), - :executable? => false + executable?: false ) - allow(ColorLS::FileInfo).to receive(:new).with("#{FIXTURES}/a.txt", link_info: true) { fileInfo } + allow(ColorLS::FileInfo).to receive(:new).with("#{FIXTURES}/a.txt", link_info: true) { file_info } expect { subject }.to output(/\S+\s+ 5 .* a.txt/mx).to_stdout end @@ -122,10 +131,10 @@ RSpec.describe ColorLS::Flags do context 'with --long flag on windows' do let(:args) { ['--long', "#{FIXTURES}/a.txt"] } - before { - ColorLS::FileInfo.class_variable_set :@@users, {} - ColorLS::FileInfo.class_variable_set :@@groups, {} - } + before do + ColorLS::FileInfo.class_variable_set :@@users, {} # rubocop:disable Style/ClassVars + ColorLS::FileInfo.class_variable_set :@@groups, {} # rubocop:disable Style/ClassVars + end it 'returns no user / group info' do expect(::Etc).to receive(:getpwuid).and_return(nil) @@ -144,13 +153,21 @@ RSpec.describe ColorLS::Flags do context 'with --sort-dirs flag' do let(:args) { ['--sort-dirs', '-1', FIXTURES] } - it('sorts results alphabetically, directories first') { expect { subject }.to output(/symlinks.+a-file.+z-file/m).to_stdout } + it('sorts results alphabetically, directories first') { + expect do + subject + end.to output(/symlinks.+a-file.+z-file/m).to_stdout + } end context 'with --sort-files flag' do let(:args) { ['--sort-files', '-1', FIXTURES] } - it('sorts results alphabetically, files first') { expect { subject }.to output(/a-file.+z-file.+symlinks/m).to_stdout } + it('sorts results alphabetically, files first') { + expect do + subject + end.to output(/a-file.+z-file.+symlinks/m).to_stdout + } end context 'with --sort=time' do @@ -174,7 +191,7 @@ RSpec.describe ColorLS::Flags do let(:args) { ['--sort=size', '--group-directories-first', '-1', FIXTURES] } it 'sorts results by size' do - expect(::STDOUT).to receive(:tty?).and_return(true) + expect($stdout).to receive(:tty?).and_return(true) expect { subject }.to output(/symlinks.+a-file.+z-file/m).to_stdout end @@ -213,7 +230,11 @@ RSpec.describe ColorLS::Flags do context 'with --sort=extension flag' do let(:args) { ['--sort=extension', '-1', FIXTURES] } - it('sorts results by extension') { expect { subject }.to output(/a-file.+symlinks.+z-file.+a.md.+a.txt.+z.txt/m).to_stdout } + it('sorts results by extension') { + expect do + subject + end.to output(/a-file.+symlinks.+z-file.+a.md.+a.txt.+z.txt/m).to_stdout + } end context 'with --dirs flag' do @@ -251,7 +272,11 @@ RSpec.describe ColorLS::Flags do let(:args) { ['--tree=1', FIXTURES] } it('displays file hierarchy') { expect { subject }.to output(/├──/).to_stdout } - it { expect { subject }.not_to output(/ReadmeLink.md|Supportlink|doesnotexisttest.txt|third-level-file.txt/).to_stdout } + it { + expect do + subject + end.not_to output(/ReadmeLink.md|Supportlink|doesnotexisttest.txt|third-level-file.txt/).to_stdout + } end context 'with --tree=3 flag' do @@ -282,7 +307,7 @@ RSpec.describe ColorLS::Flags do if File.symlink? File.join(FIXTURES, 'symlinks', 'Supportlink') expect { subject }.to output(/yaml_sort_checker.rb/).to_stdout else - skip "symlinks not supported" + skip 'symlinks not supported' end end end @@ -292,7 +317,7 @@ RSpec.describe ColorLS::Flags do it 'should issue a warning, hint about `--help` and exit' do allow(::Kernel).to receive(:warn) do |message| - expect(message).to output "--snafu" + expect(message).to output '--snafu' end expect { subject }.to raise_error('colorls exited with 2').and output(/--help/).to_stderr @@ -303,7 +328,7 @@ RSpec.describe ColorLS::Flags do let(:args) { [FIXTURES] } it 'should warn but not raise an error' do - allow(CLocale).to receive(:setlocale).with(CLocale::LC_COLLATE, '').and_raise(RuntimeError.new("setlocale error")) + allow(CLocale).to receive(:setlocale).with(CLocale::LC_COLLATE, '').and_raise(RuntimeError.new('setlocale error')) expect { subject }.to output(/setlocale error/).to_stderr.and output.to_stdout end @@ -321,7 +346,7 @@ RSpec.describe ColorLS::Flags do let(:args) { ['not_exist_file'] } it 'should exit with status code 2' do - expect {subject}.to output(/ Specified path 'not_exist_file' doesn't exist./).to_stderr + expect { subject }.to output(/ Specified path 'not_exist_file' doesn't exist./).to_stderr expect(subject).to eq 2 end end @@ -330,30 +355,30 @@ RSpec.describe ColorLS::Flags do let(:args) { ['-o', "#{FIXTURES}/a.txt"] } before do - fileInfo = instance_double( + file_info = instance_double( 'FileInfo', - :group => "sys", - :mtime => Time.now, - :directory? => false, - :owner => "user", - :name => "a.txt", - :show => "a.txt", - :nlink => 1, - :size => 128, - :blockdev? => false, - :chardev? => false, - :socket? => false, - :symlink? => false, - :stats => OpenStruct.new( + group: 'sys', + mtime: Time.now, + directory?: false, + owner: 'user', + name: 'a.txt', + show: 'a.txt', + nlink: 1, + size: 128, + blockdev?: false, + chardev?: false, + socket?: false, + symlink?: false, + stats: OpenStruct.new( mode: 0o444, # read for user, owner, other setuid?: true, setgid?: true, sticky?: true ), - :executable? => false + executable?: false ) - allow(ColorLS::FileInfo).to receive(:new).with("#{FIXTURES}/a.txt", link_info: true) { fileInfo } + allow(ColorLS::FileInfo).to receive(:new).with("#{FIXTURES}/a.txt", link_info: true) { file_info } end it 'lists without group info' do @@ -368,30 +393,30 @@ RSpec.describe ColorLS::Flags do let(:args) { ['-g', "#{FIXTURES}/a.txt"] } before do - fileInfo = instance_double( + file_info = instance_double( 'FileInfo', - :group => "sys", - :mtime => Time.now, - :directory? => false, - :owner => "user", - :name => "a.txt", - :show => "a.txt", - :nlink => 1, - :size => 128, - :blockdev? => false, - :chardev? => false, - :socket? => false, - :symlink? => false, - :stats => OpenStruct.new( + group: 'sys', + mtime: Time.now, + directory?: false, + owner: 'user', + name: 'a.txt', + show: 'a.txt', + nlink: 1, + size: 128, + blockdev?: false, + chardev?: false, + socket?: false, + symlink?: false, + stats: OpenStruct.new( mode: 0o444, # read for user, owner, other setuid?: true, setgid?: true, sticky?: true ), - :executable? => false + executable?: false ) - allow(ColorLS::FileInfo).to receive(:new).with("#{FIXTURES}/a.txt", link_info: true) { fileInfo } + allow(ColorLS::FileInfo).to receive(:new).with("#{FIXTURES}/a.txt", link_info: true) { file_info } end it 'lists with group info' do @@ -406,30 +431,30 @@ RSpec.describe ColorLS::Flags do let(:args) { ['-og', "#{FIXTURES}/a.txt"] } before do - fileInfo = instance_double( + file_info = instance_double( 'FileInfo', - :group => "sys", - :mtime => Time.now, - :directory? => false, - :owner => "user", - :name => "a.txt", - :show => "a.txt", - :nlink => 1, - :size => 128, - :blockdev? => false, - :chardev? => false, - :socket? => false, - :symlink? => false, - :stats => OpenStruct.new( + group: 'sys', + mtime: Time.now, + directory?: false, + owner: 'user', + name: 'a.txt', + show: 'a.txt', + nlink: 1, + size: 128, + blockdev?: false, + chardev?: false, + socket?: false, + symlink?: false, + stats: OpenStruct.new( mode: 0o444, # read for user, owner, other setuid?: true, setgid?: true, sticky?: true ), - :executable? => false + executable?: false ) - allow(ColorLS::FileInfo).to receive(:new).with("#{FIXTURES}/a.txt", link_info: true) { fileInfo } + allow(ColorLS::FileInfo).to receive(:new).with("#{FIXTURES}/a.txt", link_info: true) { file_info } end it 'lists without group info' do @@ -444,30 +469,30 @@ RSpec.describe ColorLS::Flags do let(:args) { ['-l', '-G', "#{FIXTURES}/a.txt"] } before do - fileInfo = instance_double( + file_info = instance_double( 'FileInfo', - :group => "sys", - :mtime => Time.now, - :directory? => false, - :owner => "user", - :name => "a.txt", - :show => "a.txt", - :nlink => 1, - :size => 128, - :blockdev? => false, - :chardev? => false, - :socket? => false, - :symlink? => false, - :stats => OpenStruct.new( + group: 'sys', + mtime: Time.now, + directory?: false, + owner: 'user', + name: 'a.txt', + show: 'a.txt', + nlink: 1, + size: 128, + blockdev?: false, + chardev?: false, + socket?: false, + symlink?: false, + stats: OpenStruct.new( mode: 0o444, # read for user, owner, other setuid?: true, setgid?: true, sticky?: true ), - :executable? => false + executable?: false ) - allow(ColorLS::FileInfo).to receive(:new).with("#{FIXTURES}/a.txt", link_info: true) { fileInfo } + allow(ColorLS::FileInfo).to receive(:new).with("#{FIXTURES}/a.txt", link_info: true) { file_info } end it 'lists without group info' do diff --git a/spec/color_ls/git_spec.rb b/spec/color_ls/git_spec.rb index 50a574f..3ccb558 100644 --- a/spec/color_ls/git_spec.rb +++ b/spec/color_ls/git_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' RSpec.describe ColorLS::Git do @@ -7,20 +9,20 @@ RSpec.describe ColorLS::Git do end def git_status(*entries) - StringIO.new entries.map { |line| line + "\x0" }.join + StringIO.new entries.map { |line| "#{line}\u0000" }.join end context 'file in repository root' do it 'should return `M`' do allow(subject).to receive(:git_prefix).with('/repo/').and_return('') - allow(subject).to receive(:git_subdir_status).and_yield(git_status(" M foo.txt")) + allow(subject).to receive(:git_subdir_status).and_yield(git_status(' M foo.txt')) expect(subject.status('/repo/')).to include('foo.txt' => Set['M']) end it 'should return `M`' do allow(subject).to receive(:git_prefix).with('/repo/').and_return('') - allow(subject).to receive(:git_subdir_status).and_yield(git_status("?? foo.txt")) + allow(subject).to receive(:git_subdir_status).and_yield(git_status('?? foo.txt')) expect(subject.status('/repo/')).to include('foo.txt' => Set['??']) end @@ -29,14 +31,14 @@ RSpec.describe ColorLS::Git do context 'file in subdir' do it 'should return `M` for subdir' do allow(subject).to receive(:git_prefix).with('/repo/').and_return('') - allow(subject).to receive(:git_subdir_status).and_yield(git_status(" M subdir/foo.txt")) + allow(subject).to receive(:git_subdir_status).and_yield(git_status(' M subdir/foo.txt')) expect(subject.status('/repo/')).to include('subdir' => Set['M']) end it 'should return `M` and `D` for subdir' do allow(subject).to receive(:git_prefix).with('/repo/').and_return('') - allow(subject).to receive(:git_subdir_status).and_yield(git_status(" M subdir/foo.txt", "D subdir/other.c")) + allow(subject).to receive(:git_subdir_status).and_yield(git_status(' M subdir/foo.txt', 'D subdir/other.c')) expect(subject.status('/repo/')).to include('subdir' => Set['M', 'D']) end diff --git a/spec/color_ls/layout_spec.rb b/spec/color_ls/layout_spec.rb index 8226171..b09e070 100644 --- a/spec/color_ls/layout_spec.rb +++ b/spec/color_ls/layout_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' RSpec.describe(ColorLS::HorizontalLayout, '#each_line') do diff --git a/spec/color_ls/monkey_spec.rb b/spec/color_ls/monkey_spec.rb index d711949..a8dea8b 100644 --- a/spec/color_ls/monkey_spec.rb +++ b/spec/color_ls/monkey_spec.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + require 'colorls/monkeys' RSpec.describe String, '#uniq' do - it 'removes all duplicate characters' do - expect('abca'.uniq).to be == 'abc' - end + it 'removes all duplicate characters' do + expect('abca'.uniq).to be == 'abc' + end end RSpec.describe String, '#colorize' do diff --git a/spec/color_ls/yaml_spec.rb b/spec/color_ls/yaml_spec.rb index b7f158c..a577188 100644 --- a/spec/color_ls/yaml_spec.rb +++ b/spec/color_ls/yaml_spec.rb @@ -1,11 +1,13 @@ +# frozen_string_literal: true + require 'spec_helper' RSpec.describe ColorLS::Yaml do ::FILENAMES = { - file_aliases: :value, + file_aliases: :value, folder_aliases: :value, - folders: :key, - files: :key + folders: :key, + files: :key }.freeze let(:base_directory) { 'lib/yaml' } diff --git a/spec/color_ls_spec.rb b/spec/color_ls_spec.rb index 3c9dc04..1fc1f30 100644 --- a/spec/color_ls_spec.rb +++ b/spec/color_ls_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' RSpec.describe ColorLS do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 876d1fe..6945b08 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'simplecov' SimpleCov.start do @@ -12,7 +14,7 @@ end require 'bundler/setup' require 'colorls' -Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |file| require file } +Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].sort.each { |file| require file } # disable rainbow globally to ease checking expected output Rainbow.enabled = false diff --git a/spec/support/yaml_sort_checker.rb b/spec/support/yaml_sort_checker.rb index d8d63aa..4aa9e79 100644 --- a/spec/support/yaml_sort_checker.rb +++ b/spec/support/yaml_sort_checker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'yaml' require 'diffy'