diff --git a/README.md b/README.md index 16de710..4c1335b 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ for the auto complete process. You can save a sample YAML file by running: ``` -$ completely new +$ completely init ``` This will generate a file named `completely.yaml` with this content: diff --git a/lib/completely/cli.rb b/lib/completely/cli.rb index 8d2f016..d5638b3 100644 --- a/lib/completely/cli.rb +++ b/lib/completely/cli.rb @@ -1,10 +1,20 @@ require 'mister_bin' -require 'completely/command' +require 'completely/commands/init' +require 'completely/commands/preview' +require 'completely/commands/generate' module Completely class CLI def self.runner - MisterBin::Runner.new handler: Command + runner = MisterBin::Runner.new version: Completely::VERSION, + header: "Completely - Bash Completions Generator", + footer: "Run !txtpur!completely COMMAND --help!txtrst! for more information" + + runner.route 'init', to: Commands::Init + runner.route 'preview', to: Commands::Preview + runner.route 'generate', to: Commands::Generate + + runner end end end diff --git a/lib/completely/command.rb b/lib/completely/command.rb deleted file mode 100644 index bb21e0c..0000000 --- a/lib/completely/command.rb +++ /dev/null @@ -1,89 +0,0 @@ -require 'completely/version' - -module Completely - class Command < MisterBin::Command - help "Bash completion script generator" - version Completely::VERSION - - usage "completely new [CONFIG_PATH]" - usage "completely preview [CONFIG_PATH --function NAME]" - usage "completely generate [CONFIG_PATH OUTPUT_PATH --function NAME --wrap NAME]" - usage "completely (-h|--help|--version)" - - command "new", "Create a new sample YAML configuration file" - command "preview", "Generate the bash completion script to STDOUT" - command "generate", "Generate the bash completion script to a file" - - option "-f --function NAME", "Modify the name of the function in the generated script" - option "-w --wrap NAME", "Wrap the completion script inside a function that echos the script. This is useful if you wish to embed it directly in your script" - - param "CONFIG_PATH", "Path to the YAML configuration file" - param "OUTPUT_PATH", "Path to the output bash script" - - example "completely new" - example "completely new input.yaml" - example "completely preview --function _my_completions" - example "completely generate" - example "completely generate input.yaml" - example "completely generate input.yaml output.sh -f _my_completions" - example "completely generate -w give_comps -f my_completions" - - def new_command - if File.exist? config_path - raise "File already exists: #{config_path}" - else - File.write config_path, sample - say "Saved !txtpur!#{config_path}" - end - end - - def preview_command - puts script - syntax_warning unless completions.valid? - end - - def generate_command - wrap = args['--wrap'] - output = wrap ? wrapper_function(wrap) : script - File.write output_path, output - say "Saved !txtpur!#{output_path}" - syntax_warning unless completions.valid? - end - - private - - def config_path - @config_path ||= args['CONFIG_PATH'] || "completely.yaml" - end - - def output_path - @output_path ||= args['OUTPUT_PATH'] || "completely.bash" - end - - def sample - @sample ||= File.read(sample_path) - end - - def sample_path - @sample_path ||= File.expand_path("sample.yaml", __dir__) - end - - def script - @script ||= completions.script - end - - def wrapper_function(wrapper_name) - completions.wrapper_function wrapper_name - end - - def completions - @completions ||= Completions.load(config_path, function_name: args['--function']) - end - - def syntax_warning - say! "\n!txtred!WARNING:\nYour configuration is invalid." - say! "!txtred!All patterns must start with the same word." - end - - end -end diff --git a/lib/completely/commands/base.rb b/lib/completely/commands/base.rb new file mode 100644 index 0000000..a5e251f --- /dev/null +++ b/lib/completely/commands/base.rb @@ -0,0 +1,37 @@ +require 'mister_bin' + +module Completely + module Commands + class Base < MisterBin::Command + + class << self + def config_path_usage + param "CONFIG_PATH", "Path to the YAML configuration file [default: completely.yaml]" + end + + def function_usage + option "-f --function NAME", "Modify the name of the function in the generated script" + end + end + + protected + + def script + @script ||= completions.script + end + + def completions + @completions ||= Completions.load(config_path, function_name: args['--function']) + end + + def config_path + args['CONFIG_PATH'] || 'completely.yaml' + end + + def syntax_warning + say! "\n!txtred!WARNING:\nYour configuration is invalid." + say! "!txtred!All patterns must start with the same word." + end + end + end +end diff --git a/lib/completely/commands/generate.rb b/lib/completely/commands/generate.rb new file mode 100644 index 0000000..866e05e --- /dev/null +++ b/lib/completely/commands/generate.rb @@ -0,0 +1,37 @@ +require 'completely/commands/base' + +module Completely + module Commands + class Generate < Base + help "Generate the bash completion script to a file" + + usage "completely generate [CONFIG_PATH OUTPUT_PATH --function NAME --wrap NAME]" + usage "completely generate (-h|--help)" + + function_usage + option "-w --wrap NAME", "Wrap the completion script inside a function that echos the script. This is useful if you wish to embed it directly in your script" + + config_path_usage + param "OUTPUT_PATH", "Path to the output bash script [default: completely.bash]" + + def run + wrap = args['--wrap'] + output = wrap ? wrapper_function(wrap) : script + File.write output_path, output + say "Saved !txtpur!#{output_path}" + syntax_warning unless completions.valid? + end + + private + + def wrapper_function(wrapper_name) + completions.wrapper_function wrapper_name + end + + def output_path + @output_path ||= args['OUTPUT_PATH'] || "completely.bash" + end + + end + end +end diff --git a/lib/completely/commands/init.rb b/lib/completely/commands/init.rb new file mode 100644 index 0000000..844c5da --- /dev/null +++ b/lib/completely/commands/init.rb @@ -0,0 +1,34 @@ +require 'completely/commands/base' + +module Completely + module Commands + class Init < Base + help "Create a new sample YAML configuration file" + + usage "completely init [CONFIG_PATH]" + usage "completely init (-h|--help)" + + config_path_usage + + def run + if File.exist? config_path + raise "File already exists: #{config_path}" + else + File.write config_path, sample + say "Saved !txtpur!#{config_path}" + end + end + + private + + def sample + @sample ||= File.read sample_path + end + + def sample_path + @sample_path ||= File.expand_path "../sample.yaml", __dir__ + end + + end + end +end diff --git a/lib/completely/commands/preview.rb b/lib/completely/commands/preview.rb new file mode 100644 index 0000000..d1f9c08 --- /dev/null +++ b/lib/completely/commands/preview.rb @@ -0,0 +1,20 @@ +require 'completely/commands/base' + +module Completely + module Commands + class Preview < Base + help "Generate the bash completion script to STDOUT" + + usage "completely preview [CONFIG_PATH --function NAME]" + usage "completely preview (-h|--help)" + + function_usage + config_path_usage + + def run + puts script + syntax_warning unless completions.valid? + end + end + end +end diff --git a/spec/approvals/cli/commands b/spec/approvals/cli/commands new file mode 100644 index 0000000..ddc8aa3 --- /dev/null +++ b/spec/approvals/cli/commands @@ -0,0 +1,8 @@ +Completely - Bash Completions Generator + +Commands: + init Create a new sample YAML configuration file + preview Generate the bash completion script to STDOUT + generate Generate the bash completion script to a file + +Run completely COMMAND --help for more information diff --git a/spec/approvals/cli/generate-path b/spec/approvals/cli/generate/custom-out-path similarity index 100% rename from spec/approvals/cli/generate-path rename to spec/approvals/cli/generate/custom-out-path diff --git a/spec/approvals/cli/generate b/spec/approvals/cli/generate/custom-path similarity index 100% rename from spec/approvals/cli/generate rename to spec/approvals/cli/generate/custom-path diff --git a/spec/approvals/cli/generate-function b/spec/approvals/cli/generate/function similarity index 100% rename from spec/approvals/cli/generate-function rename to spec/approvals/cli/generate/function diff --git a/spec/approvals/cli/generate/help b/spec/approvals/cli/generate/help new file mode 100644 index 0000000..56b3101 --- /dev/null +++ b/spec/approvals/cli/generate/help @@ -0,0 +1,23 @@ +Generate the bash completion script to a file + +Usage: + completely generate [CONFIG_PATH OUTPUT_PATH --function NAME --wrap NAME] + completely generate (-h|--help) + +Options: + -f --function NAME + Modify the name of the function in the generated script + + -w --wrap NAME + Wrap the completion script inside a function that echos the script. This is + useful if you wish to embed it directly in your script + + -h --help + Show this help + +Parameters: + CONFIG_PATH + Path to the YAML configuration file [default: completely.yaml] + + OUTPUT_PATH + Path to the output bash script [default: completely.bash] diff --git a/spec/approvals/cli/generate-wrapper b/spec/approvals/cli/generate/no-args similarity index 100% rename from spec/approvals/cli/generate-wrapper rename to spec/approvals/cli/generate/no-args diff --git a/spec/approvals/cli/generate/wrapper b/spec/approvals/cli/generate/wrapper new file mode 100644 index 0000000..98264e0 --- /dev/null +++ b/spec/approvals/cli/generate/wrapper @@ -0,0 +1 @@ +Saved completely.bash diff --git a/spec/approvals/cli/help b/spec/approvals/cli/help deleted file mode 100644 index 9b96cab..0000000 --- a/spec/approvals/cli/help +++ /dev/null @@ -1,47 +0,0 @@ -Bash completion script generator - -Usage: - completely new [CONFIG_PATH] - completely preview [CONFIG_PATH --function NAME] - completely generate [CONFIG_PATH OUTPUT_PATH --function NAME --wrap NAME] - completely (-h|--help|--version) - -Commands: - new - Create a new sample YAML configuration file - - preview - Generate the bash completion script to STDOUT - - generate - Generate the bash completion script to a file - -Options: - -f --function NAME - Modify the name of the function in the generated script - - -w --wrap NAME - Wrap the completion script inside a function that echos the script. This is - useful if you wish to embed it directly in your script - - -h --help - Show this help - - --version - Show version number - -Parameters: - CONFIG_PATH - Path to the YAML configuration file - - OUTPUT_PATH - Path to the output bash script - -Examples: - completely new - completely new input.yaml - completely preview --function _my_completions - completely generate - completely generate input.yaml - completely generate input.yaml output.sh -f _my_completions - completely generate -w give_comps -f my_completions diff --git a/spec/approvals/cli/new-path b/spec/approvals/cli/init/custom-path similarity index 100% rename from spec/approvals/cli/new-path rename to spec/approvals/cli/init/custom-path diff --git a/spec/approvals/cli/new-error b/spec/approvals/cli/init/file-exists similarity index 100% rename from spec/approvals/cli/new-error rename to spec/approvals/cli/init/file-exists diff --git a/spec/approvals/cli/init/help b/spec/approvals/cli/init/help new file mode 100644 index 0000000..06c0db8 --- /dev/null +++ b/spec/approvals/cli/init/help @@ -0,0 +1,13 @@ +Create a new sample YAML configuration file + +Usage: + completely init [CONFIG_PATH] + completely init (-h|--help) + +Options: + -h --help + Show this help + +Parameters: + CONFIG_PATH + Path to the YAML configuration file [default: completely.yaml] diff --git a/spec/approvals/cli/new b/spec/approvals/cli/init/no-args similarity index 100% rename from spec/approvals/cli/new rename to spec/approvals/cli/init/no-args diff --git a/spec/approvals/cli/preview/help b/spec/approvals/cli/preview/help new file mode 100644 index 0000000..2aab702 --- /dev/null +++ b/spec/approvals/cli/preview/help @@ -0,0 +1,16 @@ +Generate the bash completion script to STDOUT + +Usage: + completely preview [CONFIG_PATH --function NAME] + completely preview (-h|--help) + +Options: + -f --function NAME + Modify the name of the function in the generated script + + -h --help + Show this help + +Parameters: + CONFIG_PATH + Path to the YAML configuration file [default: completely.yaml] diff --git a/spec/approvals/cli/usage b/spec/approvals/cli/usage deleted file mode 100644 index 3c21439..0000000 --- a/spec/approvals/cli/usage +++ /dev/null @@ -1,5 +0,0 @@ -Usage: - completely new [CONFIG_PATH] - completely preview [CONFIG_PATH --function NAME] - completely generate [CONFIG_PATH OUTPUT_PATH --function NAME --wrap NAME] - completely (-h|--help|--version) diff --git a/spec/completely/bin_spec.rb b/spec/completely/bin_spec.rb index 072b1e4..cc866cc 100644 --- a/spec/completely/bin_spec.rb +++ b/spec/completely/bin_spec.rb @@ -3,6 +3,10 @@ describe 'bin/completely' do subject { CLI.runner } + it "shows list of commands" do + expect{ subject.run }.to output_approval('cli/commands') + end + context "on error" do it "displays it nicely" do expect(`bin/completely preview notfound.yaml 2>&1`).to match_approval('cli/error') diff --git a/spec/completely/command_spec.rb b/spec/completely/command_spec.rb deleted file mode 100644 index 9ba7c4b..0000000 --- a/spec/completely/command_spec.rb +++ /dev/null @@ -1,122 +0,0 @@ -require 'spec_helper' - -describe Command do - subject { CLI.runner } - - context "without arguments" do - it "shows long usage" do - expect { subject.run %w[] }.to output_approval('cli/usage') - end - end - - context "with --help" do - it "shows long usage" do - expect { subject.run %w[--help] }.to output_approval('cli/help') - end - end - - describe "new" do - before { system "rm -f completely.yaml" } - after { system "rm -f completely.yaml" } - let(:sample) { File.read "lib/completely/sample.yaml" } - - it "creates a new sample file named completely.yaml" do - expect { subject.run %w[new] }.to output_approval('cli/new') - expect(File.read 'completely.yaml').to eq sample - end - - context "with an argument" do - before { reset_tmp_dir } - - it "creates a new sample file named completely.yaml" do - expect { subject.run %w[new spec/tmp/in.yaml] } - .to output_approval('cli/new-path') - expect(File.read 'spec/tmp/in.yaml').to eq sample - end - end - - context "when the config file already exists" do - before { system "cp lib/completely/sample.yaml completely.yaml" } - after { system "rm -f completely.yaml" } - - it "raises an error" do - expect { subject.run %w[new] }.to raise_approval('cli/new-error') - end - end - end - - describe "preview" do - before { system "cp lib/completely/sample.yaml completely.yaml" } - after { system "rm -f completely.yaml" } - - it "outputs the generated script to STDOUT" do - expect { subject.run %w[preview] } - .to output_approval('cli/generated-script') - end - - context "with a path argument" do - it "outputs the generated script to STDOUT" do - expect { subject.run %w[preview completely.yaml] } - .to output_approval('cli/generated-script') - end - end - - context "with an invalid configuration" do - it "outputs a warning to STDERR" do - expect { subject.run %w[preview spec/fixtures/broken.yaml] } - .to output_approval('cli/warning').to_stderr - end - end - end - - describe "generate" do - before { system "cp lib/completely/sample.yaml completely.yaml" } - after { system "rm -f completely.yaml" } - - it "generates the bash script to completely.bash" do - expect { subject.run %w[generate] }.to output_approval('cli/generate') - expect(File.read "completely.bash").to match_approval('cli/generated-script') - end - - context "with a config path argument" do - it "generates the bash script to completely.bash" do - expect { subject.run %w[generate completely.yaml] }.to output_approval('cli/generate') - expect(File.read "completely.bash").to match_approval('cli/generated-script') - end - end - - context "with a config path and output path arguments" do - before { reset_tmp_dir } - - it "generates the bash script to the specified path" do - expect { subject.run %w[generate completely.yaml spec/tmp/out.bash] }.to output_approval('cli/generate-path') - expect(File.read "spec/tmp/out.bash").to match_approval('cli/generated-script') - end - end - - context "with --function NAME" do - after { system "rm -f completely.bash" } - - it "uses the provided function name" do - expect { subject.run %w[generate --function _mycomps] }.to output_approval('cli/generate-function') - expect(File.read "completely.bash").to match_approval('cli/generated-script-alt') - end - end - - context "with --wrapper NAME" do - after { system "rm -f completely.bash" } - - it "wraps the script in a function" do - expect { subject.run %w[generate --wrap give_comps] }.to output_approval('cli/generate-wrapper') - expect(File.read "completely.bash").to match_approval('cli/generated-wrapped-script') - end - end - - context "with an invalid configuration" do - it "outputs a warning to STDERR" do - expect { subject.run %w[generate spec/fixtures/broken.yaml spec/tmp/out.bash] } - .to output_approval('cli/warning').to_stderr - end - end - end -end diff --git a/spec/completely/commands/generate_spec.rb b/spec/completely/commands/generate_spec.rb new file mode 100644 index 0000000..b99f01d --- /dev/null +++ b/spec/completely/commands/generate_spec.rb @@ -0,0 +1,62 @@ +require 'spec_helper' + +describe Commands::Generate do + subject { CLI.runner } + before { system "cp lib/completely/sample.yaml completely.yaml" } + after { system "rm -f completely.yaml" } + + context "with --help" do + it "shows long usage" do + expect{ subject.run %w[generate --help] }.to output_approval('cli/generate/help') + end + end + + context "without arguments" do + it "generates the bash script to completely.bash" do + expect { subject.run %w[generate] }.to output_approval('cli/generate/no-args') + expect(File.read "completely.bash").to match_approval('cli/generated-script') + end + end + + context "with CONFIG_PATH" do + it "generates the bash script to completely.bash" do + expect { subject.run %w[generate completely.yaml] }.to output_approval('cli/generate/custom-path') + expect(File.read "completely.bash").to match_approval('cli/generated-script') + end + end + + context "with CONFIG_PATH OUTPUT_PATH" do + before { reset_tmp_dir } + + it "generates the bash script to the specified path" do + expect { subject.run %w[generate completely.yaml spec/tmp/out.bash] }.to output_approval('cli/generate/custom-out-path') + expect(File.read "spec/tmp/out.bash").to match_approval('cli/generated-script') + end + end + + context "with --function NAME" do + after { system "rm -f completely.bash" } + + it "uses the provided function name" do + expect { subject.run %w[generate --function _mycomps] }.to output_approval('cli/generate/function') + expect(File.read "completely.bash").to match_approval('cli/generated-script-alt') + end + end + + context "with --wrapper NAME" do + after { system "rm -f completely.bash" } + + it "wraps the script in a function" do + expect { subject.run %w[generate --wrap give_comps] }.to output_approval('cli/generate/wrapper') + expect(File.read "completely.bash").to match_approval('cli/generated-wrapped-script') + end + end + + context "with an invalid configuration" do + it "outputs a warning to STDERR" do + expect { subject.run %w[generate spec/fixtures/broken.yaml spec/tmp/out.bash] } + .to output_approval('cli/warning').to_stderr + end + end + +end diff --git a/spec/completely/commands/init_spec.rb b/spec/completely/commands/init_spec.rb new file mode 100644 index 0000000..2f81015 --- /dev/null +++ b/spec/completely/commands/init_spec.rb @@ -0,0 +1,41 @@ +require 'spec_helper' + +describe Commands::Init do + subject { CLI.runner } + before { system "rm -f completely.yaml" } + after { system "rm -f completely.yaml" } + let(:sample) { File.read "lib/completely/sample.yaml" } + + context "with --help" do + it "shows long usage" do + expect{ subject.run %w[init --help] }.to output_approval('cli/init/help') + end + end + + context "without arguments" do + it "creates a new sample file named completely.yaml" do + expect { subject.run %w[init] }.to output_approval('cli/init/no-args') + expect(File.read 'completely.yaml').to eq sample + end + end + + context "with CONFIG_PATH" do + before { reset_tmp_dir } + + it "creates a new sample file with the requested name" do + expect { subject.run %w[init spec/tmp/in.yaml] } + .to output_approval('cli/init/custom-path') + expect(File.read 'spec/tmp/in.yaml').to eq sample + end + end + + context "when the config file already exists" do + before { system "cp lib/completely/sample.yaml completely.yaml" } + after { system "rm -f completely.yaml" } + + it "raises an error" do + expect { subject.run %w[init] }.to raise_approval('cli/init/file-exists') + end + end + +end diff --git a/spec/completely/commands/preview_spec.rb b/spec/completely/commands/preview_spec.rb new file mode 100644 index 0000000..e71a080 --- /dev/null +++ b/spec/completely/commands/preview_spec.rb @@ -0,0 +1,35 @@ +require 'spec_helper' + +describe Commands::Preview do + subject { CLI.runner } + before { system "cp lib/completely/sample.yaml completely.yaml" } + after { system "rm -f completely.yaml" } + + context "with --help" do + it "shows long usage" do + expect{ subject.run %w[preview --help] }.to output_approval('cli/preview/help') + end + end + + context "without arguments" do + it "outputs the generated script to STDOUT" do + expect { subject.run %w[preview] } + .to output_approval('cli/generated-script') + end + end + + context "with CONFIG_PATH" do + it "outputs the generated script to STDOUT" do + expect { subject.run %w[preview completely.yaml] } + .to output_approval('cli/generated-script') + end + end + + context "with an invalid configuration" do + it "outputs a warning to STDERR" do + expect { subject.run %w[preview spec/fixtures/broken.yaml] } + .to output_approval('cli/warning').to_stderr + end + end + +end