Update matchers docs with some clarification based on user feedback.

This commit is contained in:
Jennifer Taylor 2019-10-28 17:53:06 -07:00 committed by Jennifer Taylor
parent b5789d42ad
commit f889c0993d
2 changed files with 27 additions and 8 deletions

View file

@ -156,6 +156,15 @@ but for those that do, sequence wildcard matchers offer a great degree of
flexibility. Unlike all other matcher types, these allow you to match against
more than one LibCST node, much like wildcards in regular expressions do.
LibCST does not implicitly match on partial sequences for you. So, when matching
against a sequence you will need to provide a complete pattern. This often means
using helpers such as :func:`~libcst.matchers.ZeroOrMore` as the first and last
element of your sequence. Think of it as the difference between Python's
`re.match <https://docs.python.org/3/library/re.html#re.match>`_ and
`re.fullmatch <https://docs.python.org/3/library/re.html#re.fullmatch>`_ functions.
LibCST matchers behave like the latter so that it is possible to specify sequences
which must start with, end with or be exactly equal to some pattern.
.. autoclass:: libcst.matchers.AtLeastN
.. autofunction:: libcst.matchers.ZeroOrMore
.. autoclass:: libcst.matchers.AtMostN

View file

@ -460,10 +460,12 @@ class _BaseWildcardNode:
class AtLeastN(Generic[_MatcherT], _BaseWildcardNode):
"""
Matcher that matches ``n`` or more of a particular matcher in a sequence.
Matcher that matches ``n`` or more LibCST nodes in a row in a sequence.
:class:`AtLeastN` defaults to matching against the :func:`DoNotCare` matcher,
so if you do not specify a concrete matcher as a child, :class:`AtLeastN`
will match only by count.
so if you do not specify a matcher as a child, :class:`AtLeastN`
will match only by count. If you do specify a matcher as a child,
:class:`AtLeastN` will instead make sure that each LibCST node matches the
matcher supplied.
For example, this will match all function calls with at least 3 arguments::
@ -475,7 +477,7 @@ class AtLeastN(Generic[_MatcherT], _BaseWildcardNode):
You can combine sequence matchers with concrete matchers and special matchers
and it will behave as you expect. For example, this will match all function
calls that have 2 or more integer arguments, followed by any arbitrary
calls that have 2 or more integer arguments in a row, followed by any arbitrary
argument::
m.Call(args=[m.AtLeastN(n=2, matcher=m.Arg(m.Integer())), m.DoNotCare()])
@ -547,16 +549,24 @@ def ZeroOrMore(
m.Call(args=[m.Arg(m.Integer()), m.ZeroOrMore()])
You will often want to use :class:`ZeroOrMore` on both sides of a concrete
matcher in order to match against sequences that contain a particular node
in an arbitrary location. For example, the following will match any function
call that takes in at least one string argument anywhere::
m.Call(args=[m.ZeroOrMore(), m.Arg(m.SimpleString()), m.ZeroOrMore()])
"""
return cast(AtLeastN[Union[_MatcherT, DoNotCareSentinel]], AtLeastN(matcher, n=0))
class AtMostN(Generic[_MatcherT], _BaseWildcardNode):
"""
Matcher that matches ``n`` or less of a particular matcher in a sequence.
Matcher that matches ``n`` or fewer LibCST nodes in a row in a sequence.
:class:`AtMostN` defaults to matching against the :func:`DoNotCare` matcher,
so if you do not specify a concrete matcher as a child, :class:`AtMostN` will
match only by count.
so if you do not specify a matcher as a child, :class:`AtMostN` will
match only by count. If you do specify a matcher as a child,
:class:`AtMostN` will instead make sure that each LibCST node matches the
matcher supplied.
For example, this will match all function calls with 3 or fewer arguments::
@ -568,7 +578,7 @@ class AtMostN(Generic[_MatcherT], _BaseWildcardNode):
You can combine sequence matchers with concrete matchers and special matchers
and it will behave as you expect. For example, this will match all function
calls that have 0, 1 or 2 string arguments, followed by an arbitrary
calls that have 0, 1 or 2 string arguments in a row, followed by an arbitrary
argument::
m.Call(args=[m.AtMostN(n=2, matcher=m.Arg(m.SimpleString())), m.DoNotCare()])