From a015c0f5e271e9e3c668a9c6a75d13f337baafd0 Mon Sep 17 00:00:00 2001 From: Vladimir Iakovlev Date: Sun, 15 Jan 2017 15:11:34 +0100 Subject: [PATCH] #N/A: Add gem unknown command rule --- README.md | 1 + tests/rules/test_gem_unknown_command.py | 82 +++++++++++++++++++++++++ thefuck/rules/gem_unknown_command.py | 32 ++++++++++ 3 files changed, 115 insertions(+) create mode 100644 tests/rules/test_gem_unknown_command.py create mode 100644 thefuck/rules/gem_unknown_command.py diff --git a/README.md b/README.md index 6e482727..292431fd 100644 --- a/README.md +++ b/README.md @@ -164,6 +164,7 @@ using the matched rule and runs it. Rules enabled by default are as follows: * `fab_command_not_found` – fix misspelled fabric commands; * `fix_alt_space` – replaces Alt+Space with Space character; * `fix_file` – opens a file with an error in your `$EDITOR`; +* `gem_unknown_command` – fixes wrong `gem` commands; * `git_add` – fixes *"pathspec 'foo' did not match any file(s) known to git."*; * `git_bisect_usage` – fixes `git bisect strt`, `git bisect goood`, `git bisect rset`, etc. when bisecting; * `git_branch_delete` – changes `git branch -d` to `git branch -D`; diff --git a/tests/rules/test_gem_unknown_command.py b/tests/rules/test_gem_unknown_command.py new file mode 100644 index 00000000..c5d30887 --- /dev/null +++ b/tests/rules/test_gem_unknown_command.py @@ -0,0 +1,82 @@ +import pytest +from six import BytesIO +from thefuck.rules.gem_unknown_command import match, get_new_command +from tests.utils import Command + +stderr = ''' +ERROR: While executing gem ... (Gem::CommandLineError) + Unknown command {} +''' + +gem_help_commands_stdout = b''' +GEM commands are: + + build Build a gem from a gemspec + cert Manage RubyGems certificates and signing settings + check Check a gem repository for added or missing files + cleanup Clean up old versions of installed gems + contents Display the contents of the installed gems + dependency Show the dependencies of an installed gem + environment Display information about the RubyGems environment + fetch Download a gem and place it in the current directory + generate_index Generates the index files for a gem server directory + help Provide help on the 'gem' command + install Install a gem into the local repository + list Display local gems whose name matches REGEXP + lock Generate a lockdown list of gems + mirror Mirror all gem files (requires rubygems-mirror) + open Open gem sources in editor + outdated Display all gems that need updates + owner Manage gem owners of a gem on the push server + pristine Restores installed gems to pristine condition from files + located in the gem cache + push Push a gem up to the gem server + query Query gem information in local or remote repositories + rdoc Generates RDoc for pre-installed gems + search Display remote gems whose name matches REGEXP + server Documentation and gem repository HTTP server + sources Manage the sources and cache file RubyGems uses to search + for gems + specification Display gem specification (in yaml) + stale List gems along with access times + uninstall Uninstall gems from the local repository + unpack Unpack an installed gem to the current directory + update Update installed gems to the latest version + which Find the location of a library file you can require + yank Remove a pushed gem from the index + +For help on a particular command, use 'gem help COMMAND'. + +Commands may be abbreviated, so long as they are unambiguous. +e.g. 'gem i rake' is short for 'gem install rake'. + +''' + + +@pytest.fixture(autouse=True) +def gem_help_commands(mocker): + patch = mocker.patch('subprocess.Popen') + patch.return_value.stdout = BytesIO(gem_help_commands_stdout) + return patch + + +@pytest.mark.parametrize('script, command', [ + ('gem isntall jekyll', 'isntall'), + ('gem last --local', 'last')]) +def test_match(script, command): + assert match(Command(script, stderr=stderr.format(command))) + + +@pytest.mark.parametrize('script, stderr', [ + ('gem install jekyll', ''), + ('git log', stderr.format('log'))]) +def test_not_match(script, stderr): + assert not match(Command(script, stderr=stderr)) + + +@pytest.mark.parametrize('script, stderr, result', [ + ('gem isntall jekyll', stderr.format('isntall'), 'gem install jekyll'), + ('gem last --local', stderr.format('last'), 'gem list --local')]) +def test_get_new_command(script, stderr, result): + new_command = get_new_command(Command(script, stderr=stderr)) + assert new_command[0] == result diff --git a/thefuck/rules/gem_unknown_command.py b/thefuck/rules/gem_unknown_command.py new file mode 100644 index 00000000..e20f3ba4 --- /dev/null +++ b/thefuck/rules/gem_unknown_command.py @@ -0,0 +1,32 @@ +import re +import subprocess +from thefuck.utils import for_app, eager, replace_command + + +@for_app('gem') +def match(command): + return ('ERROR: While executing gem ... (Gem::CommandLineError)' + in command.stderr + and 'Unknown command' in command.stderr) + + +def _get_unknown_command(command): + return re.findall(r'Unknown command (.*)$', command.stderr)[0] + + +@eager +def _get_all_commands(): + proc = subprocess.Popen(['gem', 'help', 'commands'], + stdout=subprocess.PIPE) + + for line in proc.stdout.readlines(): + line = line.decode() + + if line.startswith(' '): + yield line.strip().split(' ')[0] + + +def get_new_command(command): + unknown_command = _get_unknown_command(command) + all_commands = _get_all_commands() + return replace_command(command, unknown_command, all_commands)