diff options
author | Timothee Cour <timothee.cour2@gmail.com> | 2021-08-02 22:22:47 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-02 22:22:47 -0700 |
commit | c0abdaa2b4587526f235ef41186e84c4f87813e1 (patch) | |
tree | e6fa3870ff6a76c8b9226d45c8e77f0b44e6b852 | |
parent | 499d4690fbbb59b6baf1698b1ed1574dde6ea7c5 (diff) | |
download | Nim-c0abdaa2b4587526f235ef41186e84c4f87813e1.tar.gz |
improve runnableExamples and docs for std/nre (#18634)
* improve runnableExamples and docs for std/nre * avoid too long lines in example
-rw-r--r-- | lib/impure/nre.nim | 117 |
1 files changed, 49 insertions, 68 deletions
diff --git a/lib/impure/nre.nim b/lib/impure/nre.nim index 7b2d7d3ee..01ef77427 100644 --- a/lib/impure/nre.nim +++ b/lib/impure/nre.nim @@ -23,12 +23,12 @@ when defined(js): ## **Note**: If you love `sequtils.toSeq` we have bad news for you. This ## library doesn't work with it due to documented compiler limitations. As ## a workaround, use this: -## -## .. code-block:: nim -## -## import std/nre except toSeq -## -## +runnableExamples: + # either `import std/nre except toSeq` or fully qualify `sequtils.toSeq`: + import std/sequtils + iterator iota(n: int): int = + for i in 0..<n: yield i + assert sequtils.toSeq(iota(3)) == @[0, 1, 2] ## Licencing ## --------- ## @@ -36,33 +36,28 @@ when defined(js): ## this module. ## ## .. _`some additional terms`: http://pcre.sourceforge.net/license.txt -## runnableExamples: + import std/sugar let vowels = re"[aeoui]" - - let expectedResults = [ - 1 .. 1, - 2 .. 2, - 4 .. 4, - 6 .. 6, - 7 .. 7, - ] - var i = 0 - for match in "moigagoo".findIter(vowels): - doAssert match.matchBounds == expectedResults[i] - inc i + let bounds = collect: + for match in "moiga".findIter(vowels): match.matchBounds + assert bounds == @[1 .. 1, 2 .. 2, 4 .. 4] + from std/sequtils import toSeq + let s = sequtils.toSeq("moiga".findIter(vowels)) + # fully qualified to avoid confusion with nre.toSeq + assert s.len == 3 let firstVowel = "foo".find(vowels) let hasVowel = firstVowel.isSome() - if hasVowel: - let matchBounds = firstVowel.get().captureBounds[-1] - doAssert matchBounds.a == 1 + assert hasVowel + let matchBounds = firstVowel.get().captureBounds[-1] + assert matchBounds.a == 1 - ## as with module `re`, unless specified otherwise, `start` parameter in each - ## proc indicates where the scan starts, but outputs are relative to the start - ## of the input string, not to `start`: - doAssert find("uxabc", re"(?<=x|y)ab", start = 1).get.captures[-1] == "ab" - doAssert find("uxabc", re"ab", start = 3).isNone + # as with module `re`, unless specified otherwise, `start` parameter in each + # proc indicates where the scan starts, but outputs are relative to the start + # of the input string, not to `start`: + assert find("uxabc", re"(?<=x|y)ab", start = 1).get.captures[-1] == "ab" + assert find("uxabc", re"ab", start = 3).isNone from pcre import nil import nre/private/util @@ -145,7 +140,7 @@ type ## `DOLLAR_ENDONLY`, `FIRSTLINE`, `NO_AUTO_CAPTURE`, ## `JAVASCRIPT_COMPAT`, `U`, `NO_STUDY`. In other PCRE wrappers, you ## will need to pass these as separate flags to PCRE. - pattern*: string ## not nil + pattern*: string pcreObj: ptr pcre.Pcre ## not nil pcreExtra: ptr pcre.ExtraData ## nil @@ -165,21 +160,12 @@ type ## the string value of whatever was captured at that id. If the value ## is invalid, then behavior is undefined. If the id is `-1`, then ## the whole match is returned. If the given capture was not matched, - ## `nil` is returned. - ## - ## - `"abc".match(re"(\w)").get.captures[0] == "a"` - ## - `"abc".match(re"(?<letter>\w)").get.captures["letter"] == "a"` - ## - `"abc".match(re"(\w)\w").get.captures[-1] == "ab"` + ## `nil` is returned. See examples for `match`. ## ## `captureBounds[]: HSlice[int, int]` ## gets the bounds of the given capture according to the same rules as ## the above. If the capture is not filled, then `None` is returned. - ## The bounds are both inclusive. - ## - ## - `"abc".match(re"(\w)").get.captureBounds[0] == 0 .. 0` - ## - `0 in "abc".match(re"(\w)").get.captureBounds == true` - ## - `"abc".match(re"").get.captureBounds[-1] == 0 .. -1` - ## - `"abc".match(re"abc").get.captureBounds[-1] == 0 .. 2` + ## The bounds are both inclusive. See examples for `match`. ## ## `match: string` ## the full text of the match. @@ -198,7 +184,6 @@ type pattern*: Regex ## The regex doing the matching. ## Not nil. str*: string ## The string that was matched against. - ## Not nil. pcreMatchBounds: seq[HSlice[cint, cint]] ## First item is the bounds of the match ## Other items are the captures ## `a` is inclusive start, `b` is exclusive end @@ -226,18 +211,6 @@ type ## for whatever reason. The message contains the error ## code. -runnableExamples: - # This MUST be kept in sync with the examples in RegexMatch - doAssert "abc".match(re"(\w)").get.captures[0] == "a" - doAssert "abc".match(re"(?<letter>\w)").get.captures["letter"] == "a" - doAssert "abc".match(re"(\w)\w").get.captures[-1] == "ab" - - doAssert "abc".match(re"(\w)").get.captureBounds[0] == 0 .. 0 - doAssert 0 in "abc".match(re"(\w)").get.captureBounds == true - doAssert "abc".match(re"").get.captureBounds[-1] == 0 .. -1 - doAssert "abc".match(re"abc").get.captureBounds[-1] == 0 .. 2 - - proc destroyRegex(pattern: Regex) = pcre.free_substring(cast[cstring](pattern.pcreObj)) if pattern.pcreExtra != nil: @@ -540,18 +513,27 @@ proc matchImpl(str: string, pattern: Regex, start, endpos: int, flags: int): Opt proc match*(str: string, pattern: Regex, start = 0, endpos = int.high): Option[RegexMatch] = ## Like `find(...)<#find,string,Regex,int>`_, but anchored to the start of the ## string. - ## runnableExamples: - doAssert "foo".match(re"f").isSome - doAssert "foo".match(re"o").isNone + assert "foo".match(re"f").isSome + assert "foo".match(re"o").isNone + assert "abc".match(re"(\w)").get.captures[0] == "a" + assert "abc".match(re"(?<letter>\w)").get.captures["letter"] == "a" + assert "abc".match(re"(\w)\w").get.captures[-1] == "ab" + + assert "abc".match(re"(\w)").get.captureBounds[0] == 0 .. 0 + assert 0 in "abc".match(re"(\w)").get.captureBounds + assert "abc".match(re"").get.captureBounds[-1] == 0 .. -1 + assert "abc".match(re"abc").get.captureBounds[-1] == 0 .. 2 return str.matchImpl(pattern, start, endpos, pcre.ANCHORED) iterator findIter*(str: string, pattern: Regex, start = 0, endpos = int.high): RegexMatch = ## Works the same as `find(...)<#find,string,Regex,int>`_, but finds every - ## non-overlapping match. `"2222".find(re"22")` is `"22", "22"`, not - ## `"22", "22", "22"`. - ## + ## non-overlapping match: + runnableExamples: + import std/sugar + assert collect(for a in "2222".findIter(re"22"): a.match) == @["22", "22"] + # not @["22", "22", "22"] ## Arguments are the same as `find(...)<#find,string,Regex,int>`_ ## ## Variants: @@ -619,11 +601,10 @@ proc contains*(str: string, pattern: Regex, start = 0, endpos = int.high): bool ## Determine if the string contains the given pattern between the end and ## start positions: ## This function is equivalent to `isSome(str.find(pattern, start, endpos))`. - ## runnableExamples: - doAssert "abc".contains(re"bc") - doAssert not "abc".contains(re"cd") - doAssert not "abc".contains(re"a", start = 1) + assert "abc".contains(re"bc") + assert not "abc".contains(re"cd") + assert not "abc".contains(re"a", start = 1) return isSome(str.find(pattern, start, endpos)) @@ -635,16 +616,16 @@ proc split*(str: string, pattern: Regex, maxSplit = -1, start = 0): seq[string] ## runnableExamples: # - If the match is zero-width, then the string is still split: - doAssert "123".split(re"") == @["1", "2", "3"] + assert "123".split(re"") == @["1", "2", "3"] # - If the pattern has a capture in it, it is added after the string # split: - doAssert "12".split(re"(\d)") == @["", "1", "", "2", ""] + assert "12".split(re"(\d)") == @["", "1", "", "2", ""] # - If `maxsplit != -1`, then the string will only be split # `maxsplit - 1` times. This means that there will be `maxsplit` # strings in the output seq. - doAssert "1.2.3".split(re"\.", maxsplit = 2) == @["1", "2.3"] + assert "1.2.3".split(re"\.", maxsplit = 2) == @["1", "2.3"] result = @[] var lastIdx = start @@ -747,9 +728,9 @@ proc escapeRe*(str: string): string {.gcsafe.} = ## ## Escaped char: `\ + * ? [ ^ ] $ ( ) { } = ! < > | : -` runnableExamples: - doAssert escapeRe("fly+wind") == "fly\\+wind" - doAssert escapeRe("!") == "\\!" - doAssert escapeRe("nim*") == "nim\\*" + assert escapeRe("fly+wind") == "fly\\+wind" + assert escapeRe("!") == "\\!" + assert escapeRe("nim*") == "nim\\*" #([\\+*?[^\]$(){}=!<>|:-]) const SpecialCharMatcher = {'\\', '+', '*', '?', '[', '^', ']', '$', '(', |