mirror of
https://github.com/nvbn/thefuck.git
synced 2025-03-14 14:48:49 +00:00
#N/A: Add support to rules of type post match
Rules of this types are those which main functionality is usefull after they had been matched.
This commit is contained in:
parent
2d81166213
commit
db488d35eb
@ -14,9 +14,9 @@ from thefuck.types import Command
|
||||
class TestCorrectedCommand(object):
|
||||
|
||||
def test_equality(self):
|
||||
assert (CorrectedCommand('ls', None, 100) ==
|
||||
CorrectedCommand('ls', None, 200))
|
||||
assert (CorrectedCommand('ls', None, 100) !=
|
||||
assert (CorrectedCommand('ls', None, 100,) ==
|
||||
CorrectedCommand('ls', None, 200,))
|
||||
assert (CorrectedCommand('ls', None, 100,) !=
|
||||
CorrectedCommand('ls', lambda *_: _, 100))
|
||||
|
||||
def test_hashable(self):
|
||||
@ -48,16 +48,19 @@ class TestRule(object):
|
||||
def test_from_path(self, mocker):
|
||||
match = object()
|
||||
get_new_command = object()
|
||||
post_match = object()
|
||||
load_source = mocker.patch(
|
||||
'thefuck.types.load_source',
|
||||
return_value=Mock(match=match,
|
||||
get_new_command=get_new_command,
|
||||
post_match=post_match,
|
||||
enabled_by_default=True,
|
||||
priority=900,
|
||||
requires_output=True))
|
||||
requires_output=True,
|
||||
is_post_match=False))
|
||||
rule_path = os.path.join(os.sep, 'rules', 'bash.py')
|
||||
assert (Rule.from_path(Path(rule_path))
|
||||
== Rule('bash', match, get_new_command, priority=900))
|
||||
assert (Rule.from_path(Path(rule_path)) == Rule(
|
||||
'bash', rule_path, match, get_new_command, post_match, priority=900))
|
||||
load_source.assert_called_once_with('bash', rule_path)
|
||||
|
||||
@pytest.mark.parametrize('rules, exclude_rules, rule, is_enabled', [
|
||||
@ -77,16 +80,16 @@ class TestRule(object):
|
||||
assert rule.is_enabled == is_enabled
|
||||
|
||||
def test_isnt_match(self):
|
||||
assert not Rule('', lambda _: False).is_match(
|
||||
assert not Rule('', match=lambda _: False).is_match(
|
||||
Command('ls', ''))
|
||||
|
||||
def test_is_match(self):
|
||||
rule = Rule('', lambda x: x.script == 'cd ..')
|
||||
rule = Rule('', match=lambda x: x.script == 'cd ..')
|
||||
assert rule.is_match(Command('cd ..', ''))
|
||||
|
||||
@pytest.mark.usefixtures('no_colors')
|
||||
def test_isnt_match_when_rule_failed(self, capsys):
|
||||
rule = Rule('test', Mock(side_effect=OSError('Denied')),
|
||||
rule = Rule('test', match=Mock(side_effect=OSError('Denied')),
|
||||
requires_output=False)
|
||||
assert not rule.is_match(Command('ls', ''))
|
||||
assert capsys.readouterr()[1].split('\n')[0] == '[WARN] Rule test:'
|
||||
|
@ -54,13 +54,13 @@ def test_command_selector():
|
||||
class TestSelectCommand(object):
|
||||
@pytest.fixture
|
||||
def commands_with_side_effect(self):
|
||||
return [CorrectedCommand('ls', lambda *_: None, 100),
|
||||
CorrectedCommand('cd', lambda *_: None, 100)]
|
||||
return [CorrectedCommand('ls', lambda *_: None, 100, None),
|
||||
CorrectedCommand('cd', lambda *_: None, 100, None)]
|
||||
|
||||
@pytest.fixture
|
||||
def commands(self):
|
||||
return [CorrectedCommand('ls', None, 100),
|
||||
CorrectedCommand('cd', None, 100)]
|
||||
return [CorrectedCommand('ls', None, 100, None),
|
||||
CorrectedCommand('cd', None, 100, None)]
|
||||
|
||||
def test_without_commands(self, capsys):
|
||||
assert ui.select_command(iter([])) is None
|
||||
|
@ -3,18 +3,21 @@ from thefuck.const import DEFAULT_PRIORITY
|
||||
|
||||
|
||||
class Rule(types.Rule):
|
||||
def __init__(self, name='', match=lambda *_: True,
|
||||
def __init__(self, name='', path='', match=lambda *_: True,
|
||||
get_new_command=lambda *_: '',
|
||||
post_match=lambda *_: '',
|
||||
enabled_by_default=True,
|
||||
side_effect=None,
|
||||
priority=DEFAULT_PRIORITY,
|
||||
requires_output=True):
|
||||
super(Rule, self).__init__(name, match, get_new_command,
|
||||
enabled_by_default, side_effect,
|
||||
priority, requires_output)
|
||||
requires_output=True,
|
||||
is_post_match=False):
|
||||
super(Rule, self).__init__(name, path, match, get_new_command,
|
||||
post_match, enabled_by_default, side_effect,
|
||||
priority, requires_output, is_post_match)
|
||||
|
||||
|
||||
class CorrectedCommand(types.CorrectedCommand):
|
||||
def __init__(self, script='', side_effect=None, priority=DEFAULT_PRIORITY):
|
||||
def __init__(self, script='', side_effect=None,
|
||||
priority=DEFAULT_PRIORITY, rule=None):
|
||||
super(CorrectedCommand, self).__init__(
|
||||
script, side_effect, priority)
|
||||
script, side_effect, priority, rule)
|
||||
|
@ -86,9 +86,9 @@ class Command(object):
|
||||
class Rule(object):
|
||||
"""Rule for fixing commands."""
|
||||
|
||||
def __init__(self, name, match, get_new_command,
|
||||
def __init__(self, name, path, match, get_new_command, post_match,
|
||||
enabled_by_default, side_effect,
|
||||
priority, requires_output):
|
||||
priority, requires_output, is_post_match):
|
||||
"""Initializes rule with given fields.
|
||||
|
||||
:type name: basestring
|
||||
@ -101,31 +101,36 @@ class Rule(object):
|
||||
|
||||
"""
|
||||
self.name = name
|
||||
self.path = path
|
||||
self.match = match
|
||||
self.get_new_command = get_new_command
|
||||
self.post_match = post_match
|
||||
self.enabled_by_default = enabled_by_default
|
||||
self.side_effect = side_effect
|
||||
self.priority = priority
|
||||
self.requires_output = requires_output
|
||||
self.is_post_match = is_post_match
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, Rule):
|
||||
return ((self.name, self.match, self.get_new_command,
|
||||
self.enabled_by_default, self.side_effect,
|
||||
self.priority, self.requires_output)
|
||||
== (other.name, other.match, other.get_new_command,
|
||||
other.enabled_by_default, other.side_effect,
|
||||
other.priority, other.requires_output))
|
||||
return ((self.name, self.path, self.match, self.get_new_command,
|
||||
self.post_match, self.enabled_by_default,
|
||||
self.side_effect, self.priority,
|
||||
self.requires_output, self.is_post_match)
|
||||
== (other.name, other.path, other.match, other.get_new_command,
|
||||
other.post_match, other.enabled_by_default,
|
||||
other.side_effect, other.priority,
|
||||
other.requires_output, other.is_post_match))
|
||||
else:
|
||||
return False
|
||||
|
||||
def __repr__(self):
|
||||
return 'Rule(name={}, match={}, get_new_command={}, ' \
|
||||
'enabled_by_default={}, side_effect={}, ' \
|
||||
'priority={}, requires_output)'.format(
|
||||
self.name, self.match, self.get_new_command,
|
||||
self.enabled_by_default, self.side_effect,
|
||||
self.priority, self.requires_output)
|
||||
return 'Rule(name={}, path={}, match={}, get_new_command={}, ' \
|
||||
'post_match={}, enabled_by_default={}, side_effect={}, ' \
|
||||
'priority={}, requires_output={}, is_post_match={})'.format(
|
||||
self.name, self.path, self.match, self.get_new_command,
|
||||
self.post_match, self.enabled_by_default, self.side_effect,
|
||||
self.priority, self.requires_output, self.is_post_match)
|
||||
|
||||
@classmethod
|
||||
def from_path(cls, path):
|
||||
@ -139,12 +144,14 @@ class Rule(object):
|
||||
with logs.debug_time(u'Importing rule: {};'.format(name)):
|
||||
rule_module = load_source(name, str(path))
|
||||
priority = getattr(rule_module, 'priority', DEFAULT_PRIORITY)
|
||||
return cls(name, rule_module.match,
|
||||
return cls(name, path.as_posix(), rule_module.match,
|
||||
rule_module.get_new_command,
|
||||
getattr(rule_module, 'post_match', None),
|
||||
getattr(rule_module, 'enabled_by_default', True),
|
||||
getattr(rule_module, 'side_effect', None),
|
||||
settings.priority.get(name, priority),
|
||||
getattr(rule_module, 'requires_output', True))
|
||||
getattr(rule_module, 'requires_output', True),
|
||||
getattr(rule_module, 'is_post_match', False))
|
||||
|
||||
@property
|
||||
def is_enabled(self):
|
||||
@ -192,13 +199,14 @@ class Rule(object):
|
||||
for n, new_command in enumerate(new_commands):
|
||||
yield CorrectedCommand(script=new_command,
|
||||
side_effect=self.side_effect,
|
||||
priority=(n + 1) * self.priority)
|
||||
priority=(n + 1) * self.priority,
|
||||
rule=self)
|
||||
|
||||
|
||||
class CorrectedCommand(object):
|
||||
"""Corrected by rule command."""
|
||||
|
||||
def __init__(self, script, side_effect, priority):
|
||||
def __init__(self, script, side_effect, priority, rule):
|
||||
"""Initializes instance with given fields.
|
||||
|
||||
:type script: basestring
|
||||
@ -209,6 +217,7 @@ class CorrectedCommand(object):
|
||||
self.script = script
|
||||
self.side_effect = side_effect
|
||||
self.priority = priority
|
||||
self.rule = rule
|
||||
|
||||
def __eq__(self, other):
|
||||
"""Ignores `priority` field."""
|
||||
@ -225,14 +234,19 @@ class CorrectedCommand(object):
|
||||
return u'CorrectedCommand(script={}, side_effect={}, priority={})'.format(
|
||||
self.script, self.side_effect, self.priority)
|
||||
|
||||
def _get_script(self):
|
||||
def _get_script(self, old_cmd):
|
||||
"""Returns fixed commands script.
|
||||
|
||||
If `settings.repeat` is `True`, appends command with second attempt
|
||||
of running fuck in case fixed command fails again.
|
||||
|
||||
"""
|
||||
if settings.repeat:
|
||||
if self.rule and self.rule.is_post_match:
|
||||
return u'thefuck --post-match {} {} {}'.format(
|
||||
self.rule.path,
|
||||
shell.quote(old_cmd.script),
|
||||
shell.quote(old_cmd.output))
|
||||
elif settings.repeat:
|
||||
repeat_fuck = '{} --repeat {}--force-command {}'.format(
|
||||
get_alias(),
|
||||
'--debug ' if settings.debug else '',
|
||||
@ -255,4 +269,4 @@ class CorrectedCommand(object):
|
||||
logs.debug(u'PYTHONIOENCODING: {}'.format(
|
||||
os.environ.get('PYTHONIOENCODING', '!!not-set!!')))
|
||||
|
||||
print(self._get_script())
|
||||
print(self._get_script(old_cmd))
|
||||
|
Loading…
x
Reference in New Issue
Block a user