Update Case Sensitivity arguments (#3741)

Implements https://www.pivotaltracker.com/story/show/183314956
This commit is contained in:
Radosław Waśko 2022-09-27 22:15:52 +02:00 committed by GitHub
parent 3239815957
commit 7da4d61484
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 734 additions and 627 deletions

View File

@ -25,10 +25,12 @@ new custom_comparator=Nothing =
Specifies how to compare Text values within the Comparator.
for_text_ordering : Text_Ordering -> ObjectComparator
for_text_ordering text_ordering =
case_sensitivity = text_ordering.case_sensitivity.if_nothing Case_Sensitivity.Sensitive
case text_ordering.sort_digits_as_numbers of
True ->
txt_cmp a b = Natural_Order.compare a b text_ordering.case_sensitive . to_sign
txt_cmp a b = Natural_Order.compare a b case_sensitivity . to_sign
new.withCustomTextComparator txt_cmp
False -> case text_ordering.case_sensitive of
Case_Insensitive_Data locale -> new.withCaseInsensitivity locale.java_locale
_ -> new
False -> case case_sensitivity of
Case_Sensitivity.Sensitive -> new
Case_Sensitivity.Insensitive locale ->
new.withCaseInsensitivity locale.java_locale

View File

@ -14,11 +14,11 @@ polyglot java import com.ibm.icu.text.BreakIterator
Sort a vector of texts according to the natural dictionary ordering.
["a2", "a1", "a100", "a001", "a0001"].sort by=Natural_Order.compare . should_equal ["a0001", "a001", "a1", "a2", "a100"]
compare : Text -> Text -> (True|Case_Insensitive) Ordering
compare text1 text2 case_sensitive=True =
compare_text = case case_sensitive of
Case_Insensitive_Data locale -> a -> b -> a.compare_to_ignore_case b locale
_ -> _.compare_to _
compare : Text -> Text -> Case_Sensitivity -> Ordering
compare text1 text2 case_sensitivity=Case_Sensitivity.Sensitive =
compare_text = case case_sensitivity of
Case_Sensitivity.Insensitive locale -> a -> b -> a.compare_to_ignore_case b locale
Case_Sensitivity.Sensitive -> _.compare_to _
iter1 = BreakIterator.getCharacterInstance
iter1.setText text1

View File

@ -17,22 +17,11 @@ type Case
## First letter of each word in upper case, rest in lower case.
Title
# TODO Dubious constructor export
from project.Data.Text.Case.Case_Insensitive import all
from project.Data.Text.Case.Case_Insensitive export all
## Represents case-insensitive comparison mode.
Arguments:
- locale: The locale used for the comparison.
type Case_Insensitive
Case_Insensitive_Data locale=Locale.default
## PRIVATE
Creates a Java `TextFoldingStrategy` from the case sensitivity setting.
folding_strategy : (True|Case_Insensitive) -> TextFoldingStrategy
folding_strategy case_sensitive = case case_sensitive of
True -> TextFoldingStrategy.unicodeNormalizedFold
Case_Insensitive_Data locale ->
Creates a Java `TextFoldingStrategy` from the case sensitivity setting.
folding_strategy : Case_Sensitivity -> TextFoldingStrategy
folding_strategy case_sensitivity = case case_sensitivity of
Case_Sensitivity.Sensitive -> TextFoldingStrategy.unicodeNormalizedFold
Case_Sensitivity.Insensitive locale ->
TextFoldingStrategy.caseInsensitiveFold locale.java_locale

View File

@ -0,0 +1,15 @@
from Standard.Base import all
# TODO Dubious constructor export
from project.Data.Text.Case_Sensitivity.Case_Sensitivity import all
from project.Data.Text.Case_Sensitivity.Case_Sensitivity export all
type Case_Sensitivity
## Represents a case-sensitive comparison mode.
Sensitive
## Represents a case-insensitive comparison mode.
Arguments:
- locale: The locale used for the comparison.
Insensitive locale=Locale.default

View File

@ -351,20 +351,20 @@ Text.find self pattern mode=Regex_Mode.All match_ascii=Nothing case_insensitive=
> Example
Split the text on a regex pattern.
"abc--def==>ghi".split "[-=>]+" Regex_Matcher == ["abc", "def", "ghi"]
"abc--def==>ghi".split "[-=>]+" Regex_Matcher.Regex_Matcher_Data == ["abc", "def", "ghi"]
> Example
Split the text on any whitespace.
'abc def\tghi'.split '\\s+' Regex_Matcher == ["abc", "def", "ghi"]
'abc def\tghi'.split '\\s+' Regex_Matcher.Regex_Matcher_Data == ["abc", "def", "ghi"]
Text.split : Text -> (Text_Matcher | Regex_Matcher) -> Vector.Vector Text
Text.split self delimiter="," matcher=Text_Matcher_Data = if delimiter.is_empty then Error.throw (Illegal_Argument_Error_Data "The delimiter cannot be empty.") else
case matcher of
Text_Matcher_Data case_sensitivity ->
delimiters = Vector.from_polyglot_array <| case case_sensitivity of
True ->
Text.split self delimiter="," matcher=Text_Matcher.Case_Sensitive = if delimiter.is_empty then Error.throw (Illegal_Argument_Error_Data "The delimiter cannot be empty.") else
case Meta.type_of matcher of
Text_Matcher.Text_Matcher ->
delimiters = Vector.from_polyglot_array <| case matcher of
Text_Matcher.Case_Sensitive ->
Text_Utils.span_of_all self delimiter
Case_Insensitive_Data locale ->
Text_Matcher.Case_Insensitive locale ->
Text_Utils.span_of_all_case_insensitive self delimiter locale.java_locale
Vector.new delimiters.length+1 i->
start = if i == 0 then 0 else
@ -372,7 +372,7 @@ Text.split self delimiter="," matcher=Text_Matcher_Data = if delimiter.is_empty
end = if i == delimiters.length then (Text_Utils.char_length self) else
delimiters.at i . codeunit_start
Text_Utils.substring self start end
Regex_Matcher_Data _ _ _ _ _ ->
Regex_Matcher.Regex_Matcher ->
compiled_pattern = matcher.compile delimiter
compiled_pattern.split self mode=Regex_Mode.All
@ -453,14 +453,14 @@ Text.split self delimiter="," matcher=Text_Matcher_Data = if delimiter.is_empty
"aaa aaa".replace "aa" "c" mode=Matching_Mode.First matcher=Regex_Matcher . should_equal "ca aaa"
"aaa aaa".replace "aa" "c" mode=Matching_Mode.Last matcher=Regex_Matcher . should_equal "aaa ca"
Text.replace : Text -> Text -> Matching_Mode | Regex_Mode -> (Text_Matcher | Regex_Matcher) -> Text
Text.replace self term="" new_text="" mode=Regex_Mode.All matcher=Text_Matcher_Data = if term.is_empty then self else
case matcher of
Text_Matcher_Data case_sensitivity ->
Text.replace self term="" new_text="" mode=Regex_Mode.All matcher=Text_Matcher.Case_Sensitive = if term.is_empty then self else
case Meta.type_of matcher of
Text_Matcher.Text_Matcher ->
array_from_single_result result = case result of
Nothing -> Array.empty
_ -> Array.new_1 result
spans_array = case case_sensitivity of
True -> case mode of
spans_array = case matcher of
Text_Matcher.Case_Sensitive -> case mode of
Regex_Mode.All ->
Text_Utils.span_of_all self term
Matching_Mode.First ->
@ -468,7 +468,7 @@ Text.replace self term="" new_text="" mode=Regex_Mode.All matcher=Text_Matcher_D
Matching_Mode.Last ->
array_from_single_result <| Text_Utils.last_span_of self term
_ -> Error.throw (Illegal_Argument_Error_Data "Invalid mode.")
Case_Insensitive_Data locale -> case mode of
Text_Matcher.Case_Insensitive locale -> case mode of
Regex_Mode.All ->
Text_Utils.span_of_all_case_insensitive self term locale.java_locale
Matching_Mode.First ->
@ -479,7 +479,7 @@ Text.replace self term="" new_text="" mode=Regex_Mode.All matcher=Text_Matcher_D
Text_Utils.span_of_case_insensitive self term locale.java_locale True
_ -> Error.throw (Illegal_Argument_Error_Data "Invalid mode.")
Text_Utils.replace_spans self spans_array new_text
Regex_Matcher_Data _ _ _ _ _ ->
Regex_Matcher.Regex_Matcher ->
compiled_pattern = matcher.compile term
compiled_pattern.replace self new_text mode=mode
@ -892,12 +892,11 @@ Text.from_codepoints codepoints = Text_Utils.from_codepoints codepoints.to_array
"Hello!".starts_with "[a-z]" Regex_Matcher == False
"Hello!".starts_with "[A-Z]" Regex_Matcher == True
Text.starts_with : Text -> Matcher -> Boolean
Text.starts_with self prefix matcher=Text_Matcher_Data = case matcher of
Text_Matcher_Data case_sensitivity -> case case_sensitivity of
True -> Text_Utils.starts_with self prefix
Case_Insensitive_Data locale ->
Text.starts_with self prefix matcher=Text_Matcher.Case_Sensitive = case matcher of
Text_Matcher.Case_Sensitive -> Text_Utils.starts_with self prefix
Text_Matcher.Case_Insensitive locale ->
self.take (Text_Sub_Range.First prefix.length) . equals_ignore_case prefix locale=locale
Regex_Matcher_Data _ _ _ _ _ ->
Regex_Matcher.Regex_Matcher_Data _ _ _ _ _ ->
preprocessed_pattern = "\A(?:" + prefix + ")"
compiled_pattern = matcher.compile preprocessed_pattern
match = compiled_pattern.match self Regex_Mode.First
@ -928,12 +927,11 @@ Text.starts_with self prefix matcher=Text_Matcher_Data = case matcher of
"Hello World".ends_with "world" (Text_Matcher Case_Insensitive) == True
"Hello World".ends_with "[A-Z][a-z]{4}" Regex_Matcher == True
Text.ends_with : Text -> Matcher -> Boolean
Text.ends_with self suffix matcher=Text_Matcher_Data = case matcher of
Text_Matcher_Data case_sensitivity -> case case_sensitivity of
True -> Text_Utils.ends_with self suffix
Case_Insensitive_Data locale ->
Text.ends_with self suffix matcher=Text_Matcher.Case_Sensitive = case matcher of
Text_Matcher.Case_Sensitive -> Text_Utils.ends_with self suffix
Text_Matcher.Case_Insensitive locale ->
self.take (Text_Sub_Range.Last suffix.length) . equals_ignore_case suffix locale=locale
Regex_Matcher_Data _ _ _ _ _ ->
Regex_Matcher.Regex_Matcher_Data _ _ _ _ _ ->
preprocessed_pattern = "(?:" + suffix + ")\z"
compiled_pattern = matcher.compile preprocessed_pattern
match = compiled_pattern.match self Regex_Mode.First
@ -991,12 +989,11 @@ Text.ends_with self suffix matcher=Text_Matcher_Data = case matcher of
"Hello!".contains "[a-z]" Regex_Matcher
Text.contains : Text -> Matcher -> Boolean
Text.contains self term="" matcher=Text_Matcher_Data = case matcher of
Text_Matcher_Data case_sensitivity -> case case_sensitivity of
True -> Text_Utils.contains self term
Case_Insensitive_Data locale ->
Text.contains self term="" matcher=Text_Matcher.Case_Sensitive = case matcher of
Text_Matcher.Case_Sensitive -> Text_Utils.contains self term
Text_Matcher.Case_Insensitive locale ->
Text_Utils.contains_case_insensitive self term locale.java_locale
Regex_Matcher_Data _ _ _ _ _ ->
Regex_Matcher.Regex_Matcher_Data _ _ _ _ _ ->
compiled_pattern = matcher.compile term
match = compiled_pattern.match self Regex_Mode.First
match.is_nothing.not
@ -1372,34 +1369,33 @@ Text.trim self where=Location.Both what=_.is_whitespace =
"aaa aaa".location_of "aa" mode=Matching_Mode.Last matcher=Text_Matcher == Span (Range 5 7) "aaa aaa"
"aaa aaa".location_of "aa" mode=Matching_Mode.Last matcher=Regex_Matcher == Span (Range 4 6) "aaa aaa"
Text.location_of : Text -> (Matching_Mode.First | Matching_Mode.Last) -> Matcher -> Span | Nothing
Text.location_of self term="" mode=Matching_Mode.First matcher=Text_Matcher_Data = case matcher of
Text_Matcher_Data case_sensitive -> case case_sensitive of
True ->
codepoint_span = case mode of
Matching_Mode.First -> Text_Utils.span_of self term
Matching_Mode.Last -> Text_Utils.last_span_of self term
if codepoint_span.is_nothing then Nothing else
start = Text_Utils.utf16_index_to_grapheme_index self codepoint_span.codeunit_start
## While the codepoint_span may have different code unit length
from our term, the `length` counted in grapheme clusters is
guaranteed to be the same.
end = start + term.length
Span_Data (Range_Data start end) self
Case_Insensitive_Data locale -> case term.is_empty of
True -> case mode of
Matching_Mode.First -> Span_Data (Range_Data 0 0) self
Matching_Mode.Last ->
end = self.length
Span_Data (Range_Data end end) self
False ->
search_for_last = case mode of
Matching_Mode.First -> False
Matching_Mode.Last -> True
case Text_Utils.span_of_case_insensitive self term locale.java_locale search_for_last of
Nothing -> Nothing
grapheme_span ->
Span_Data (Range_Data grapheme_span.grapheme_start grapheme_span.grapheme_end) self
Regex_Matcher_Data _ _ _ _ _ -> case mode of
Text.location_of self term="" mode=Matching_Mode.First matcher=Text_Matcher.Case_Sensitive = case matcher of
Text_Matcher.Case_Sensitive ->
codepoint_span = case mode of
Matching_Mode.First -> Text_Utils.span_of self term
Matching_Mode.Last -> Text_Utils.last_span_of self term
if codepoint_span.is_nothing then Nothing else
start = Text_Utils.utf16_index_to_grapheme_index self codepoint_span.codeunit_start
## While the codepoint_span may have different code unit length
from our term, the `length` counted in grapheme clusters is
guaranteed to be the same.
end = start + term.length
Span_Data (Range_Data start end) self
Text_Matcher.Case_Insensitive locale -> case term.is_empty of
True -> case mode of
Matching_Mode.First -> Span_Data (Range_Data 0 0) self
Matching_Mode.Last ->
end = self.length
Span_Data (Range_Data end end) self
False ->
search_for_last = case mode of
Matching_Mode.First -> False
Matching_Mode.Last -> True
case Text_Utils.span_of_case_insensitive self term locale.java_locale search_for_last of
Nothing -> Nothing
grapheme_span ->
Span_Data (Range_Data grapheme_span.grapheme_start grapheme_span.grapheme_end) self
_ -> case mode of
Matching_Mode.First ->
case matcher.compile term . match self Matching_Mode.First of
Nothing -> Nothing
@ -1475,23 +1471,22 @@ Text.location_of self term="" mode=Matching_Mode.First matcher=Text_Matcher_Data
match_2 = ligatures . location_of_all "ffiff" matcher=(Text_Matcher Case_Insensitive)
match_2 . map .length == [2, 5]
Text.location_of_all : Text -> Matcher -> [Span]
Text.location_of_all self term="" matcher=Text_Matcher_Data = case matcher of
Text_Matcher_Data case_sensitive -> if term.is_empty then Vector.new (self.length + 1) (ix -> Span_Data (Range_Data ix ix) self) else case case_sensitive of
True ->
codepoint_spans = Vector.from_polyglot_array <| Text_Utils.span_of_all self term
grahpeme_ixes = Vector.from_polyglot_array <| Text_Utils.utf16_indices_to_grapheme_indices self (codepoint_spans.map .codeunit_start).to_array
## While the codepoint_spans may have different code unit lengths
from our term, the `length` counted in grapheme clusters is
guaranteed to be the same.
offset = term.length
grahpeme_ixes . map start->
end = start+offset
Span_Data (Range_Data start end) self
Case_Insensitive_Data locale ->
grapheme_spans = Vector.from_polyglot_array <| Text_Utils.span_of_all_case_insensitive self term locale.java_locale
grapheme_spans.map grapheme_span->
Span_Data (Range_Data grapheme_span.grapheme_start grapheme_span.grapheme_end) self
Regex_Matcher_Data _ _ _ _ _ ->
Text.location_of_all self term="" matcher=Text_Matcher.Case_Sensitive = if term.is_empty then Vector.new (self.length + 1) (ix -> Span_Data (Range_Data ix ix) self) else case matcher of
Text_Matcher.Case_Sensitive ->
codepoint_spans = Vector.from_polyglot_array <| Text_Utils.span_of_all self term
grahpeme_ixes = Vector.from_polyglot_array <| Text_Utils.utf16_indices_to_grapheme_indices self (codepoint_spans.map .codeunit_start).to_array
## While the codepoint_spans may have different code unit lengths
from our term, the `length` counted in grapheme clusters is
guaranteed to be the same.
offset = term.length
grahpeme_ixes . map start->
end = start+offset
Span_Data (Range_Data start end) self
Text_Matcher.Case_Insensitive locale ->
grapheme_spans = Vector.from_polyglot_array <| Text_Utils.span_of_all_case_insensitive self term locale.java_locale
grapheme_spans.map grapheme_span->
Span_Data (Range_Data grapheme_span.grapheme_start grapheme_span.grapheme_end) self
Regex_Matcher.Regex_Matcher_Data _ _ _ _ _ ->
case matcher.compile term . match self Regex_Mode.All of
Nothing -> []
matches -> matches.map m-> m.span 0 . to_grapheme_span

View File

@ -1,6 +1,5 @@
from Standard.Base import all
from Standard.Base.Data.Text.Case import Case_Insensitive, Case_Insensitive_Data
from Standard.Base.Error.Problem_Behavior import Report_Warning
from Standard.Base.Error.Common import Wrapped_Dataflow_Error_Data
@ -17,181 +16,6 @@ type No_Matches_Found
to_display_text self =
"The criteria "+self.criteria.to_text+" did not match any names in the input."
# TODO Dubious constructor export
from project.Data.Text.Matching.Text_Matcher import all
from project.Data.Text.Matching.Text_Matcher export all
## Represents exact text matching mode.
Arguments:
- case_sensitive: Case Sensitive if True. Otherwise, the comparison is case
insensitive using the specified locale.
type Text_Matcher
Text_Matcher_Data (case_sensitive : (True | Case_Insensitive) = True)
## UNSTABLE
Checks if a name matches the provided criterion according to the specified
matching strategy.
Arguments:
- name: A `Text` representing the name being matched.
- criterion: A `Text` representing the name to be matched.
> Example
Check if the provided name matches a regular expression.
Text_Matcher.match_single_criterion "Foobar" "foo" == False
match_single_criterion : Text -> Text -> Boolean
match_single_criterion self name criterion =
case self.case_sensitive of
True -> name == criterion
Case_Insensitive_Data locale -> name.equals_ignore_case criterion locale=locale
## UNSTABLE
Selects objects from an input list that match any of the provided criteria.
Arguments:
- objects: A list of objects to be matched.
- criteria: A list of texts representing the matching criteria. Their meaning
depends on the matching strategy.
- reorder: Specifies whether to reorder the matched objects according to the
order of the matching criteria.
If `False`, the matched entries are returned in the same order as in the
input.
If `True`, the matched entries are returned in the order of the criteria
matching them. If a single object has been matched by multiple criteria, it
is placed in the group belonging to the first matching criterion on the
list.
If a single criterion's group has more than one element, their relative
order is the same as in the input.
- name_mapper: A function mapping a provided object to its name, which will
then be matched with the criteria. It is set to the identity function by
default, thus allowing the input to be a list of names to match. But it can
be overridden to enable matching more complex objects.
- matcher: A `Matcher` instance specifying how to interpret the criterion.
- on_problems: Specifies the behavior when a problem occurs during the
function.
By default, a warning is issued, but the operation proceeds.
If set to `Report_Error`, the operation fails with a dataflow error.
If set to `Ignore`, the operation proceeds without errors or warnings.
> Example
Selects objects matching one of the provided patterns, preserving the input order.
Regex_Matcher case_sensitive=True . match_criteria ["foo", "foobar", "quux", "baz", "Foo"] [".*ba.*", "f.*"] == ["foo", "foobar", "baz"]
> Example
Selects pairs matching their first element with the provided criteria and
ordering the result according to the order of criteria that matched them.
Text_Matcher.match_criteria [Pair_Data "foo" 42, Pair_Data "bar" 33, Pair_Data "baz" 10, Pair_Data "foo" 0, Pair_Data 10 10] ["bar", "foo"] reorder=True name_mapper=_.name == [Pair_Data "bar" 33, Pair_Data "foo" 42, Pair_Data "foo" 0]
match_criteria : Vector Any -> Vector Text -> Boolean -> (Any -> Text) -> Problem_Behavior -> Vector Any ! No_Matches_Found
match_criteria self = match_criteria_implementation self
# TODO Dubious constructor export
from project.Data.Text.Matching.Regex_Matcher import all
from project.Data.Text.Matching.Regex_Matcher export all
## Represents regex matching mode.
Arguments:
- case_sensitive: Enables or disables case-insensitive matching. Case
insensitive matching behaves as if it normalizes the case of all input text
before matching on it.
- multiline: Enables or disables the multiline option. Multiline specifies
that the `^` and `$` pattern characters match the start and end of lines,
as to well as the start and end of the input, respectively.
- match_ascii: Enables or disables pure-ASCII matching for the regex. If you
know your data only contains ASCII, you can enable this for a performance
boost on some regex engines.
- dot_matches_newline: Enables or disables the dot matches newline option.
This specifies that the `.` special character should match everything
_including_ newline characters. Without this flag, it matches all
characters _except_ newlines.
- comments: Enables or disables the comments mode for the regular expression.
In comments mode, the following changes apply:
- Whitespace within the pattern is ignored, except when within a character
class or when preceded by an unescaped backslash, or within grouping
constructs (e.g. `(?...)`).
- When a line contains a `#` that is not in a character class and is not
preceded by an unescaped backslash, all characters from the leftmost such
`#` to the end of the line are ignored. That is to say; they act as
'comments' in the regex.
type Regex_Matcher
Regex_Matcher_Data (case_sensitive : (True | Case_Insensitive) = True) (multiline : Boolean = False) (match_ascii : Boolean = False) (dot_matches_newline : Boolean = False) (comments : Boolean = False)
## UNSTABLE
Compiles a provided pattern according to the rules defined in this
`Regex_Matcher`.
compile : Text -> Pattern
compile self pattern =
case_insensitive = case self.case_sensitive of
True -> False
## TODO [RW] Currently locale is not supported in case-insensitive
Regex matching. There are plans to revisit it:
https://www.pivotaltracker.com/story/show/181313576
Case_Insensitive_Data _ -> True
compiled_pattern = Regex.compile pattern case_insensitive=case_insensitive match_ascii=self.match_ascii dot_matches_newline=self.dot_matches_newline multiline=self.multiline comments=self.comments
compiled_pattern
## UNSTABLE
Checks if a name matches the provided criterion according to the specified
matching strategy.
Arguments:
- name: A `Text` representing the name being matched.
- criterion: A `Text` representing the regular expression specifying the
matching criterion.
> Example
Check if the provided name matches a regular expression.
Regex_Matcher case_sensitive=Case_Insensitive . match_single_criterion "Foobar" "f.*" == True
match_single_criterion : Text -> Text -> Boolean
match_single_criterion self name criterion =
self.compile criterion . matches name
## UNSTABLE
Selects objects from an input list that match any of the provided criteria.
Arguments:
- objects: A list of objects to be matched.
- criteria: A list of texts representing the matching criteria. Their meaning
depends on the matching strategy.
- reorder: Specifies whether to reorder the matched objects according to the
order of the matching criteria.
If `False`, the matched entries are returned in the same order as in the
input.
If `True`, the matched entries are returned in the order of the criteria
matching them. If a single object has been matched by multiple criteria, it
is placed in the group belonging to the first matching criterion on the
list.
If a single criterion's group has more than one element, their relative
order is the same as in the input.
- name_mapper: A function mapping a provided object to its name, which will
then be matched with the criteria. It is set to the identity function by
default, thus allowing the input to be a list of names to match. But it can
be overridden to enable matching more complex objects.
- matcher: A `Matcher` instance specifying how to interpret the criterion.
- on_problems: Specifies the behavior when a problem occurs during the
function.
By default, a warning is issued, but the operation proceeds.
If set to `Report_Error`, the operation fails with a dataflow error.
If set to `Ignore`, the operation proceeds without errors or warnings.
> Example
Selects objects matching one of the provided patterns, preserving the input order.
Regex_Matcher case_sensitive=True . match_criteria ["foo", "foobar", "quux", "baz", "Foo"] [".*ba.*", "f.*"] == ["foo", "foobar", "baz"]
> Example
Selects pairs matching their first element with the provided criteria and
ordering the result according to the order of criteria that matched them.
Text_Matcher.match_criteria [Pair_Data "foo" 42, Pair_Data "bar" 33, Pair_Data "baz" 10, Pair_Data "foo" 0, Pair_Data 10 10] ["bar", "foo"] reorder=True name_mapper=_.name == [Pair_Data "bar" 33, Pair_Data "foo" 42, Pair_Data "foo" 0]
match_criteria : Vector Any -> Vector Text -> Boolean -> (Any -> Text) -> Problem_Behavior -> Vector Any ! No_Matches_Found
match_criteria self = match_criteria_implementation self
## PRIVATE
match_criteria_implementation matcher objects criteria reorder=False name_mapper=(x->x) on_problems=Report_Warning =
result = internal_match_criteria_implementation matcher objects criteria reorder name_mapper

View File

@ -0,0 +1,106 @@
from Standard.Base import all
from Standard.Base.Data.Text.Matching import match_criteria_implementation
# TODO Dubious constructor export
from project.Data.Text.Regex_Matcher.Regex_Matcher import all
from project.Data.Text.Regex_Matcher.Regex_Matcher export all
## Represents regex matching mode.
type Regex_Matcher
## Regex matching mode.
Arguments:
- case_sensitivity: Specifies whether the matching should be case
sensitive.
- multiline: Enables or disables the multiline option. Multiline
specifies that the `^` and `$` pattern characters match the start and
end of lines, as to well as the start and end of the input,
respectively.
- match_ascii: Enables or disables pure-ASCII matching for the regex. If
you know your data only contains ASCII, you can enable this for a
performance boost on some regex engines.
- dot_matches_newline: Enables or disables the dot matches newline
option. This specifies that the `.` special character should match
everything _including_ newline characters. Without this flag, it
matches all characters _except_ newlines.
- comments: Enables or disables the comments mode for the regular
expression. In comments mode, the following changes apply:
- Whitespace within the pattern is ignored, except when within a
character class or when preceded by an unescaped backslash, or within
grouping constructs (e.g. `(?...)`).
- When a line contains a `#` that is not in a character class and is
not preceded by an unescaped backslash, all characters from the
leftmost such `#` to the end of the line are ignored. That is to say;
they act as 'comments' in the regex.
Regex_Matcher_Data (case_sensitivity : Case_Sensitivity = Case_Sensitivity.Sensitive) (multiline : Boolean = False) (match_ascii : Boolean = False) (dot_matches_newline : Boolean = False) (comments : Boolean = False)
## UNSTABLE
Compiles a provided pattern according to the rules defined in this
`Regex_Matcher`.
compile : Text -> Pattern
compile self pattern =
case_insensitive = case self.case_sensitivity of
Case_Sensitivity.Sensitive -> False
## TODO [RW] Currently locale is not supported in case-insensitive
Regex matching. There are plans to revisit it:
https://www.pivotaltracker.com/story/show/181313576
Case_Sensitivity.Insensitive _ -> True
Regex.compile pattern case_insensitive=case_insensitive match_ascii=self.match_ascii dot_matches_newline=self.dot_matches_newline multiline=self.multiline comments=self.comments
## UNSTABLE
Checks if a name matches the provided criterion according to the specified
matching strategy.
Arguments:
- name: A `Text` representing the name being matched.
- criterion: A `Text` representing the regular expression specifying the
matching criterion.
> Example
Check if the provided name matches a regular expression.
(Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Insensitive) . match_single_criterion "Foobar" "f.*" == True
match_single_criterion : Text -> Text -> Boolean
match_single_criterion self name criterion =
self.compile criterion . matches name
## UNSTABLE
Selects objects from an input list that match any of the provided criteria.
Arguments:
- objects: A list of objects to be matched.
- criteria: A list of texts representing the matching criteria. Their meaning
depends on the matching strategy.
- reorder: Specifies whether to reorder the matched objects according to the
order of the matching criteria.
If `False`, the matched entries are returned in the same order as in the
input.
If `True`, the matched entries are returned in the order of the criteria
matching them. If a single object has been matched by multiple criteria, it
is placed in the group belonging to the first matching criterion on the
list.
If a single criterion's group has more than one element, their relative
order is the same as in the input.
- name_mapper: A function mapping a provided object to its name, which will
then be matched with the criteria. It is set to the identity function by
default, thus allowing the input to be a list of names to match. But it can
be overridden to enable matching more complex objects.
- matcher: A `Matcher` instance specifying how to interpret the criterion.
- on_problems: Specifies the behavior when a problem occurs during the
function.
By default, a warning is issued, but the operation proceeds.
If set to `Report_Error`, the operation fails with a dataflow error.
If set to `Ignore`, the operation proceeds without errors or warnings.
> Example
Selects objects matching one of the provided patterns, preserving the input order.
Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive . match_criteria ["foo", "foobar", "quux", "baz", "Foo"] [".*ba.*", "f.*"] == ["foo", "foobar", "baz"]
> Example
Selects pairs matching their first element with the provided criteria and
ordering the result according to the order of criteria that matched them.
Text_Matcher.match_criteria [Pair_Data "foo" 42, Pair_Data "bar" 33, Pair_Data "baz" 10, Pair_Data "foo" 0, Pair_Data 10 10] ["bar", "foo"] reorder=True name_mapper=_.name == [Pair_Data "bar" 33, Pair_Data "foo" 42, Pair_Data "foo" 0]
match_criteria : Vector Any -> Vector Text -> Boolean -> (Any -> Text) -> Problem_Behavior -> Vector Any ! No_Matches_Found
match_criteria self = match_criteria_implementation self

View File

@ -0,0 +1,72 @@
from Standard.Base import all
from Standard.Base.Data.Text.Matching import match_criteria_implementation
# TODO Dubious constructor export
from project.Data.Text.Text_Matcher.Text_Matcher import all
from project.Data.Text.Text_Matcher.Text_Matcher export all
## Represents exact text matching mode.
type Text_Matcher
## Represents exact text matching mode.
Case_Sensitive
## Represents case-insensitive text matching mode.
Case_Insensitive (locale:Locale=Locale.default)
## UNSTABLE
Checks if a name matches the provided criterion according to the specified
matching strategy.
Arguments:
- name: A `Text` representing the name being matched.
- criterion: A `Text` representing the name to be matched.
> Example
Check if the provided name matches a regular expression.
Text_Matcher.match_single_criterion "Foobar" "foo" == False
match_single_criterion : Text -> Text -> Boolean
match_single_criterion self name criterion = case self of
Case_Sensitive -> name == criterion
Case_Insensitive locale -> name.equals_ignore_case criterion locale=locale
## UNSTABLE
Selects objects from an input list that match any of the provided criteria.
Arguments:
- objects: A list of objects to be matched.
- criteria: A list of texts representing the matching criteria. Their meaning
depends on the matching strategy.
- reorder: Specifies whether to reorder the matched objects according to the
order of the matching criteria.
If `False`, the matched entries are returned in the same order as in the
input.
If `True`, the matched entries are returned in the order of the criteria
matching them. If a single object has been matched by multiple criteria, it
is placed in the group belonging to the first matching criterion on the
list.
If a single criterion's group has more than one element, their relative
order is the same as in the input.
- name_mapper: A function mapping a provided object to its name, which will
then be matched with the criteria. It is set to the identity function by
default, thus allowing the input to be a list of names to match. But it can
be overridden to enable matching more complex objects.
- matcher: A `Matcher` instance specifying how to interpret the criterion.
- on_problems: Specifies the behavior when a problem occurs during the
function.
By default, a warning is issued, but the operation proceeds.
If set to `Report_Error`, the operation fails with a dataflow error.
If set to `Ignore`, the operation proceeds without errors or warnings.
> Example
Selects objects matching one of the provided patterns, preserving the input order.
Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive . match_criteria ["foo", "foobar", "quux", "baz", "Foo"] [".*ba.*", "f.*"] == ["foo", "foobar", "baz"]
> Example
Selects pairs matching their first element with the provided criteria and
ordering the result according to the order of criteria that matched them.
Text_Matcher.match_criteria [Pair_Data "foo" 42, Pair_Data "bar" 33, Pair_Data "baz" 10, Pair_Data "foo" 0, Pair_Data 10 10] ["bar", "foo"] reorder=True name_mapper=_.name == [Pair_Data "bar" 33, Pair_Data "foo" 42, Pair_Data "foo" 0]
match_criteria : Vector Any -> Vector Text -> Boolean -> (Any -> Text) -> Problem_Behavior -> Vector Any ! No_Matches_Found
match_criteria self = match_criteria_implementation self

View File

@ -4,14 +4,47 @@ from Standard.Base import all
from project.Data.Text.Text_Ordering.Text_Ordering import all
from project.Data.Text.Text_Ordering.Text_Ordering export all
## Specifies an ordering of text values.
Arguments:
- sort_digits_as_numbers: Sort digits in the text as numbers. Setting this to
`True` results in a "Natural" ordering.
- case_sensitive: Specifies if the ordering should be case case sensitive. If
set to `Nothing` (the default), it chooses the default ordering for a given
backend. For the In-memory backend, the default ordering is case sensitive.
In databases, the default ordering depends on the database configuration.
type Text_Ordering
Text_Ordering_Data (sort_digits_as_numbers:Boolean=False) (case_sensitive:(Nothing|True|Case_Insensitive)=Nothing)
## Specifies the ordering of text values.
For the In-memory backend, the default ordering is case-sensitive. In
databases, the default ordering depends on the database configuration.
Arguments:
- sort_digits_as_numbers: Sort digits in the text as numbers. Setting
this to `True` results in a "Natural" ordering.
Default (sort_digits_as_numbers:Boolean=False)
## Case sensitive ordering of values.
It will ensure case-sensitive ordering regardless of backend defaults.
This may make database queries more complicated and may result in being
unable to rely on existing indices, thus potentially making the queries
much slower. The `Default` ordering is preferred wherever possible.
Arguments:
- sort_digits_as_numbers: Sort digits in the text as numbers. Setting
this to `True` results in a "Natural" ordering.
Case_Sensitive (sort_digits_as_numbers:Boolean=False)
## Case sensitive ordering of values.
It will ensure case-insensitive ordering regardless of backend defaults.
This may make database queries more complicated and may result in being
unable to rely on existing indices, thus potentially making the queries
much slower. The `Default` ordering is preferred wherever possible.
Arguments:
- sort_digits_as_numbers: Sort digits in the text as numbers. Setting
this to `True` results in a "Natural" ordering.
Case_Insensitive (locale:Locale=Locale.default) (sort_digits_as_numbers:Boolean=False)
## PRIVATE
Returns this ordering's case sensitivity setting. It will return
`Nothing` for the `Default` ordering, meaning that the case sensitivity
is to be determined by the backend.
case_sensitivity : Case_Sensitivity
case_sensitivity self = case self of
Default _ -> Nothing
Case_Sensitive _ -> Case_Sensitivity.Sensitive
Case_Insensitive locale _ -> Case_Sensitivity.Insensitive locale

View File

@ -20,9 +20,12 @@ import project.Data.Statistics
import project.Data.Statistics.Rank_Method
import project.Data.Text
import project.Data.Text.Case
import project.Data.Text.Case_Sensitivity
import project.Data.Text.Encoding
import project.Data.Text.Extensions
import project.Data.Text.Matching
import project.Data.Text.Text_Matcher
import project.Data.Text.Regex_Matcher
import project.Data.Text.Text_Ordering
import project.Data.Text.Span
import project.Data.Time.Date
@ -63,8 +66,12 @@ export project.Data.Ordering.Sort_Direction
export project.Data.Regression
export project.Data.Statistics
export project.Data.Statistics.Rank_Method
export project.Data.Text.Case_Sensitivity
export project.Data.Text.Regex
export project.Data.Text.Regex.Regex_Mode
export project.Data.Text.Text_Ordering
export project.Data.Text.Text_Matcher
export project.Data.Text.Regex_Matcher
export project.Data.Time.Date
export project.Data.Time.Date_Time
export project.Data.Time.Time_Of_Day
@ -99,11 +106,9 @@ from project.Data.Range export all
https://www.pivotaltracker.com/story/show/181403340
https://www.pivotaltracker.com/story/show/181309938
from project.Data.Text.Extensions export Text, Line_Ending_Style, Case, Location, Matching_Mode
from project.Data.Text.Matching export Text_Matcher_Data, Regex_Matcher_Data, No_Matches_Found_Data
from project.Data.Text.Case export Case_Insensitive_Data, Text_Matcher_Data, Regex_Matcher_Data, No_Matches_Found_Data
from project.Data.Text export all hiding Encoding, Span, Text_Ordering
from project.Data.Text.Matching export No_Matches_Found_Data
from project.Data.Text export all hiding Encoding, Span
from project.Data.Text.Encoding export Encoding, Encoding_Error, Encoding_Error_Data
from project.Data.Text.Text_Ordering export all
from project.Data.Text.Span export all
from project.Error.Common export all
from project.Function export all

View File

@ -156,7 +156,7 @@ type SQL_Type
match more possible types.
is_likely_text : Boolean
is_likely_text self =
self.is_definitely_text || self.name.contains "text" (Text_Matcher_Data Case_Insensitive_Data)
self.is_definitely_text || self.name.contains "text" Text_Matcher.Case_Insensitive
# TODO Dubious constructor export

View File

@ -133,7 +133,7 @@ type Table
> Example
Select columns matching a regular expression.
table.select_columns (By_Name ["foo.+", "b.*"] (Regex_Matcher case_sensitive=Case_Insensitive))
table.select_columns (By_Name ["foo.+", "b.*"] (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Insensitive))
> Example
Select the first two columns and the last column, moving the last one to front.
@ -184,7 +184,7 @@ type Table
> Example
Remove columns matching a regular expression.
table.remove_columns (By_Name ["foo.+", "b.*"] (Regex_Matcher case_sensitive=Case_Insensitive))
table.remove_columns (By_Name ["foo.+", "b.*"] (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Insensitive))
> Example
Remove the first two columns and the last column.
@ -233,7 +233,7 @@ type Table
> Example
Move columns matching a regular expression to front, keeping columns matching "foo.+" before columns matching "b.*".
table.reorder_columns (By_Name ["foo.+", "b.*"] (Regex_Matcher case_sensitive=Case_Insensitive))
table.reorder_columns (By_Name ["foo.+", "b.*"] (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Insensitive))
> Example
Swap the first two columns.
@ -270,14 +270,14 @@ type Table
> Example
Sort columns according to the natural case-insensitive ordering.
table.sort_columns text_ordering=(Text_Ordering_Data sort_digits_as_numbers=True case_sensitive=Case_Insensitive)
table.sort_columns text_ordering=(Text_Ordering.Case_Insensitive sort_digits_as_numbers=True)
> Example
Sort columns in descending order.
table.reorder_columns Sort_Direction.Descending
sort_columns : Sort_Direction -> Text_Ordering -> Table
sort_columns self direction=Sort_Direction.Ascending text_ordering=Text_Ordering_Data =
sort_columns self direction=Sort_Direction.Ascending text_ordering=Text_Ordering.Default =
new_columns = Table_Helpers.sort_columns internal_columns=self.internal_columns direction text_ordering
self.updated_columns new_columns
@ -530,7 +530,7 @@ type Table
table.order_by (Sort_Column_Selector.By_Index [1, Sort_Column.Index -7 Sort_Direction.Descending])
order_by : Sort_Column_Selector -> Text_Ordering -> Problem_Behavior -> Table
order_by self (columns = (Sort_Column_Selector.By_Name [(Sort_Column.Name (self.columns.at 0 . name))])) text_ordering=Text_Ordering_Data on_problems=Report_Warning = Panic.handle_wrapped_dataflow_error <|
order_by self (columns = (Sort_Column_Selector.By_Name [(Sort_Column.Name (self.columns.at 0 . name))])) text_ordering=Text_Ordering.Default on_problems=Report_Warning = Panic.handle_wrapped_dataflow_error <|
problem_builder = Problem_Builder.new
columns_for_ordering = Table_Helpers.prepare_order_by self.columns columns problem_builder
problem_builder.attach_problems_before on_problems <|
@ -556,7 +556,7 @@ type Table
Arguments:
- columns: The columns of the table to use for distinguishing the rows.
- case_sensitive: Specifies if the text values should be compared case
- case_sensitivity: Specifies if the text values should be compared case
sensitively.
- on_problems: Specifies how to handle if a problem occurs, raising as a
warning by default.
@ -572,9 +572,9 @@ type Table
- If no valid columns are selected, a `No_Input_Columns_Selected`.
- If floating points values are present in the distinct columns, a
`Floating_Point_Grouping` warning.
distinct : Column_Selector -> (True|Case_Insensitive) -> Problem_Behavior -> Table
distinct self (columns = By_Name (self.columns.map .name)) case_sensitive=True on_problems=Report_Warning =
_ = [columns, case_sensitive, on_problems]
distinct : Column_Selector -> Case_Sensitivity -> Problem_Behavior -> Table
distinct self (columns = By_Name (self.columns.map .name)) case_sensitivity=Case_Sensitivity.Sensitive on_problems=Report_Warning =
_ = [columns, case_sensitivity, on_problems]
Error.throw (Unsupported_Database_Operation_Error_Data "`Table.distinct` is not yet implemented for the database backend.")
## UNSTABLE

View File

@ -1,5 +1,4 @@
from Standard.Base import all hiding First, Last
from Standard.Base.Data.Text.Text_Ordering import Text_Ordering_Data
from Standard.Table.Data.Aggregate_Column import all
import Standard.Database.Internal.IR
@ -40,14 +39,14 @@ make_expression aggregate dialect =
First c _ ignore_nothing order_by -> case is_non_empty_selector order_by of
False -> Error.throw (Unsupported_Database_Operation_Error_Data "`First` aggregation requires at least one `order_by` column.")
True ->
order_bys = order_by.columns.map c-> dialect.prepare_order_descriptor c.column.as_internal c.direction Text_Ordering_Data
order_bys = order_by.columns.map c-> dialect.prepare_order_descriptor c.column.as_internal c.direction Text_Ordering.Default
case ignore_nothing of
False -> IR.Operation "FIRST" [c.expression]+order_bys
True -> IR.Operation "FIRST_NOT_NULL" [c.expression]+order_bys
Last c _ ignore_nothing order_by -> case is_non_empty_selector order_by of
False -> Error.throw (Unsupported_Database_Operation_Error_Data "`Last` aggregation requires at least one `order_by` column.")
True ->
order_bys = order_by.columns.map c-> dialect.prepare_order_descriptor c.column.as_internal c.direction Text_Ordering_Data
order_bys = order_by.columns.map c-> dialect.prepare_order_descriptor c.column.as_internal c.direction Text_Ordering.Default
case ignore_nothing of
False -> IR.Operation "LAST" [c.expression]+order_bys
True -> IR.Operation "LAST_NOT_NULL" [c.expression]+order_bys

View File

@ -231,12 +231,12 @@ make_order_descriptor internal_column sort_direction text_ordering =
True ->
## In the future we can modify this error to suggest using a custom defined collation.
if text_ordering.sort_digits_as_numbers then Error.throw (Unsupported_Database_Operation_Error "Natural ordering is currently not supported. You may need to materialize the Table to perform this operation.") else
case text_ordering.case_sensitive of
case text_ordering.case_sensitivity of
Nothing ->
IR.Order_Descriptor_Data internal_column.expression sort_direction nulls_order=nulls collation=Nothing
True ->
Case_Sensitivity.Sensitive ->
IR.Order_Descriptor_Data internal_column.expression sort_direction nulls_order=nulls collation="ucs_basic"
Case_Insensitive_Data locale -> case locale == Locale.default of
Case_Sensitivity.Insensitive locale -> case locale == Locale.default of
False ->
Error.throw (Unsupported_Database_Operation_Error "Case insensitive ordering with custom locale is currently not supported. You may need to materialize the Table to perform this operation.")
True ->

View File

@ -57,12 +57,12 @@ type SQLite_Dialect
prepare_order_descriptor self internal_column sort_direction text_ordering = case internal_column.sql_type.is_likely_text of
True ->
if text_ordering.sort_digits_as_numbers then Error.throw (Unsupported_Database_Operation_Error_Data "Natural ordering is not supported by the SQLite backend. You may need to materialize the Table to perform this operation.") else
case text_ordering.case_sensitive of
case text_ordering.case_sensitivity of
Nothing ->
IR.Order_Descriptor_Data internal_column.expression sort_direction collation=Nothing
True ->
Case_Sensitivity.Sensitive ->
IR.Order_Descriptor_Data internal_column.expression sort_direction collation="BINARY"
Case_Insensitive_Data locale -> case locale == Locale.default of
Case_Sensitivity.Insensitive locale -> case locale == Locale.default of
False ->
Error.throw (Unsupported_Database_Operation_Error_Data "Case insensitive ordering with custom locale is not supported by the SQLite backend. You may need to materialize the Table to perform this operation.")
True ->

View File

@ -13,7 +13,7 @@ type Column_Name_Mapping
The `matcher` can be used to specify if the names should be matched
exactly or should be treated as regular expressions. It also allows to
specify if the matching should be case-sensitive.
By_Name (names : Map Text Text) (matcher : Matcher = Text_Matcher_Data)
By_Name (names : Map Text Text) (matcher : Matcher = Text_Matcher.Case_Sensitive)
## Selects columns by their index.

View File

@ -13,7 +13,7 @@ type Column_Selector
The `matcher` can be used to specify if the names should be matched
exactly or should be treated as regular expressions. It also allows to
specify if the matching should be case-sensitive.
By_Name (names : Vector Text) (matcher : Matcher = Text_Matcher_Data)
By_Name (names : Vector Text) (matcher : Matcher = Text_Matcher.Case_Sensitive)
## Selects columns by their index.

View File

@ -7,6 +7,6 @@ from project.Data.Sort_Column_Selector.Sort_Column_Selector import all
from project.Data.Sort_Column_Selector.Sort_Column_Selector export all
type Sort_Column_Selector
By_Name (columns : Vector (Sort_Column.Name | Text)) (matcher:Matcher=Text_Matcher_Data)
By_Name (columns : Vector (Sort_Column.Name | Text)) (matcher:Matcher=Text_Matcher.Case_Sensitive)
By_Index (columns : Vector (Sort_Column.Index | Integer))
By_Column (columns : Vector (Sort_Column.Column | Column))

View File

@ -309,7 +309,7 @@ type Table
> Example
Select columns matching a regular expression.
table.select_columns (By_Name ["foo.+", "b.*"] (Regex_Matcher case_sensitive=Case_Insensitive))
table.select_columns (By_Name ["foo.+", "b.*"] (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Insensitive))
> Example
Select the first two columns and the last column, moving the last one to front.
@ -360,7 +360,7 @@ type Table
> Example
Remove columns matching a regular expression.
table.remove_columns (By_Name ["foo.+", "b.*"] (Regex_Matcher case_sensitive=Case_Insensitive))
table.remove_columns (By_Name ["foo.+", "b.*"] (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Insensitive))
> Example
Remove the first two columns and the last column.
@ -409,7 +409,7 @@ type Table
> Example
Move columns matching a regular expression to front, keeping columns matching "foo.+" before columns matching "b.*".
table.reorder_columns (By_Name ["foo.+", "b.*"] (Regex_Matcher case_sensitive=Case_Insensitive))
table.reorder_columns (By_Name ["foo.+", "b.*"] (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Insensitive))
> Example
Swap the first two columns.
@ -447,14 +447,14 @@ type Table
> Example
Sort columns according to the natural case-insensitive ordering.
table.sort_columns text_ordering=(Text_Ordering_Data sort_digits_as_numbers=True case_sensitive=Case_Insensitive)
table.sort_columns text_ordering=(Text_Ordering.Case_Insensitive sort_digits_as_numbers=True)
> Example
Sort columns in descending order.
table.reorder_columns Sort_Direction.Descending
sort_columns : Sort_Direction -> Text_Ordering -> Table
sort_columns self direction=Sort_Direction.Ascending text_ordering=Text_Ordering_Data =
sort_columns self direction=Sort_Direction.Ascending text_ordering=Text_Ordering.Default =
new_columns = Table_Helpers.sort_columns internal_columns=self.columns direction text_ordering
new new_columns
@ -651,7 +651,7 @@ type Table
table.order_by (Sort_Column_Selector.By_Name ["total_stock", Sort_Column.Name "sold_stock" Sort_Direction.Descending])
order_by : Sort_Column_Selector -> Text_Ordering -> Problem_Behavior -> Table
order_by self (columns = (Sort_Column_Selector.By_Name [(Sort_Column.Name (self.columns.at 0 . name))])) text_ordering=Text_Ordering_Data on_problems=Report_Warning =
order_by self (columns = (Sort_Column_Selector.By_Name [(Sort_Column.Name (self.columns.at 0 . name))])) text_ordering=Text_Ordering.Default on_problems=Report_Warning =
problem_builder = Problem_Builder.new
columns_for_ordering = Table_Helpers.prepare_order_by self.columns columns problem_builder
problem_builder.attach_problems_before on_problems <|
@ -673,7 +673,7 @@ type Table
Arguments:
- columns: The columns of the table to use for distinguishing the rows.
- case_sensitive: Specifies if the text values should be compared case
- case_sensitivity: Specifies if the text values should be compared case
sensitively.
- on_problems: Specifies how to handle if a problem occurs, raising as a
warning by default.
@ -689,15 +689,15 @@ type Table
- If no valid columns are selected, a `No_Input_Columns_Selected`.
- If floating points values are present in the distinct columns, a
`Floating_Point_Grouping` warning.
distinct : Column_Selector -> (True|Case_Insensitive) -> Problem_Behavior -> Table
distinct self (columns = By_Name (self.columns.map .name)) case_sensitive=True on_problems=Report_Warning =
distinct : Column_Selector -> Case_Sensitivity -> Problem_Behavior -> Table
distinct self (columns = By_Name (self.columns.map .name)) case_sensitivity=Case_Sensitivity.Sensitive on_problems=Report_Warning =
warning_mapper error = case error of
No_Output_Columns -> Maybe.Some No_Input_Columns_Selected
_ -> Nothing
key_columns = Warning.map_warnings_and_errors warning_mapper <|
Table_Helpers.select_columns internal_columns=self.columns selector=columns reorder=True on_problems=on_problems
java_columns = key_columns.map .java_column
text_folding_strategy = Case.folding_strategy case_sensitive
text_folding_strategy = Case.folding_strategy case_sensitivity
java_table = Illegal_Argument_Error.handle_java_exception <|
self.java_table.distinct java_columns.to_array text_folding_strategy
on_problems.attach_problems_after (Table_Data java_table) <|

View File

@ -143,11 +143,11 @@ rename_columns internal_columns mapping on_problems =
Nothing -> Nothing
_ ->
matched.add index
new_name = case ms of
Regex_Matcher_Data _ _ _ _ _ ->
new_name = case Meta.type_of ms of
Regex_Matcher.Regex_Matcher ->
pattern = ms.compile ((good_names.at index).at 0)
pattern.replace name ((good_names.at index).at 1)
Text_Matcher_Data _ -> (good_names.at index).at 1
Text_Matcher.Text_Matcher -> (good_names.at index).at 1
unique.make_unique new_name
new_names = 0.up_to col_count . map i->(mapper (internal_columns.at i).name)
@ -156,7 +156,7 @@ rename_columns internal_columns mapping on_problems =
new_names
mapped = case mapping of
Column_Name_Mapping.By_Column vec -> name_mapper (vec.map r-> [r.at 0 . name, r.at 1]) (Text_Matcher_Data case_sensitive=True)
Column_Name_Mapping.By_Column vec -> name_mapper (vec.map r-> [r.at 0 . name, r.at 1]) Text_Matcher.Case_Sensitive
Column_Name_Mapping.By_Name map ms -> name_mapper map.to_vector ms
Column_Name_Mapping.By_Index map ->
good_indices = validate_indices col_count map.keys problem_builder
@ -204,10 +204,10 @@ rename_columns internal_columns mapping on_problems =
- text_ordering: The sort methodology to use.
sort_columns : Vector -> Sort_Direction -> Text_Ordering -> Vector
sort_columns internal_columns direction text_ordering =
case_sensitive = text_ordering.case_sensitive.if_nothing True
mapper = case case_sensitive of
True -> _.name
Case_Insensitive_Data locale ->
case_sensitivity = text_ordering.case_sensitivity.if_nothing Case_Sensitivity.Sensitive
mapper = case case_sensitivity of
Case_Sensitivity.Sensitive -> _.name
Case_Sensitivity.Insensitive locale ->
col -> col.name.to_case_insensitive_key locale=locale
comparator = case text_ordering.sort_digits_as_numbers of
True -> Natural_Order.compare
@ -245,7 +245,7 @@ select_columns_helper internal_columns selector reorder problem_builder = case s
select_indices_preserving_order internal_columns good_indices
By_Column columns ->
column_names = columns.map .name
new_selector = By_Name column_names (Text_Matcher_Data case_sensitive=True)
new_selector = By_Name column_names Text_Matcher.Case_Sensitive
select_columns_helper internal_columns new_selector reorder=reorder problem_builder=problem_builder
## PRIVATE
@ -254,7 +254,7 @@ select_columns_helper internal_columns selector reorder problem_builder = case s
resolve_column_helper : Vector a -> (Integer | Text | Column) -> Problem_Builder -> a | Nothing
resolve_column_helper internal_columns selector problem_builder = case selector of
Text ->
matched_columns = Matching.match_criteria_callback (Text_Matcher_Data case_sensitive=True) internal_columns [selector] reorder=True name_mapper=(_.name) problem_callback=problem_builder.report_missing_input_columns
matched_columns = Matching.match_criteria_callback Text_Matcher.Case_Sensitive internal_columns [selector] reorder=True name_mapper=(_.name) problem_callback=problem_builder.report_missing_input_columns
if matched_columns.length == 1 then matched_columns.first else
if matched_columns.length == 0 then Nothing else
Panic.throw (Illegal_State_Error_Data "A single exact match should never match more than one column. Perhaps the table breaks the invariant of unique column names?")
@ -465,7 +465,7 @@ transform_columns_by_column_reference internal_columns column_selectors problem_
name_extractor = selector->
column = column_extractor selector
column.name
transform_columns_by_name internal_columns column_selectors (Text_Matcher_Data case_sensitive=True) problem_builder name_extractor
transform_columns_by_name internal_columns column_selectors Text_Matcher.Case_Sensitive problem_builder name_extractor
## PRIVATE
A helper function which can be used by methods that select a subset of
@ -551,4 +551,4 @@ select_columns_by_column_reference internal_columns column_selectors problem_bui
name_extractor = selector->
column = column_extractor selector
column.name
select_columns_by_name internal_columns column_selectors (Text_Matcher_Data case_sensitive=True) problem_builder name_extractor
select_columns_by_name internal_columns column_selectors Text_Matcher.Case_Sensitive problem_builder name_extractor

View File

@ -3,9 +3,11 @@ package org.enso.interpreter.runtime.number;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.api.library.ExportLibrary;
import com.oracle.truffle.api.library.ExportMessage;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.runtime.Context;
import org.enso.interpreter.runtime.data.Type;
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
@ -44,6 +46,71 @@ public class EnsoBigInteger implements TruffleObject {
return value.toString();
}
@ExportMessage
boolean isNumber() {
return true;
}
@ExportMessage
final boolean fitsInByte() {
return false;
}
@ExportMessage
final boolean fitsInShort() {
return false;
}
@ExportMessage
final boolean fitsInInt() {
return false;
}
@ExportMessage
final boolean fitsInLong() {
return false;
}
@ExportMessage
final boolean fitsInFloat() {
return false;
}
@ExportMessage
final boolean fitsInDouble() {
return false;
}
@ExportMessage
final byte asByte() throws UnsupportedMessageException {
throw UnsupportedMessageException.create();
}
@ExportMessage
final short asShort() throws UnsupportedMessageException {
throw UnsupportedMessageException.create();
}
@ExportMessage
final int asInt() throws UnsupportedMessageException {
throw UnsupportedMessageException.create();
}
@ExportMessage
final long asLong() throws UnsupportedMessageException {
throw UnsupportedMessageException.create();
}
@ExportMessage
final float asFloat() throws UnsupportedMessageException {
throw UnsupportedMessageException.create();
}
@ExportMessage
final double asDouble() throws UnsupportedMessageException {
throw UnsupportedMessageException.create();
}
@ExportMessage
boolean hasType() {
return true;

View File

@ -24,7 +24,7 @@ main =
Bench.measure (check_all big_random ["AAAAAA"] Text_Matcher) suite_prefix+" exact" 10 10
Bench.measure (check_all big_random ["AAAAAA"] (Text_Matcher Sort_Direction)) suite_prefix+" case-insensitive" 10 10
Bench.measure (check_all big_random ["AAAAAA"] Regex_Matcher) suite_prefix+" exact regex" 10 10
Bench.measure (check_all big_random ["AAAAAA"] (Regex_Matcher case_sensitive=Case_Insensitive)) suite_prefix+" case-insensitive regex" 10 10
Bench.measure (check_all big_random ["AAAAAA"] (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Insensitive)) suite_prefix+" case-insensitive regex" 10 10
Bench.measure (check_all big_random ["A.{5000}A"] Regex_Matcher) suite_prefix+" const-width regex" 10 10
Bench.measure (check_all big_random ["AAAAA.*AAAAA"] Regex_Matcher) suite_prefix+" wildcard regex" 10 10

View File

@ -80,7 +80,7 @@ spec prefix table_builder test_selection pending=Nothing =
Test.group prefix+"Table.select_columns" pending=pending <|
Test.specify "should work as shown in the doc examples" <|
expect_column_names ["foo", "bar"] <| table.select_columns (By_Name ["bar", "foo"])
expect_column_names ["bar", "Baz", "foo_1", "foo_2"] <| table.select_columns (By_Name ["foo.+", "b.*"] (Regex_Matcher_Data case_sensitive=Case_Insensitive_Data))
expect_column_names ["bar", "Baz", "foo_1", "foo_2"] <| table.select_columns (By_Name ["foo.+", "b.*"] (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Insensitive))
expect_column_names ["abcd123", "foo", "bar"] <| table.select_columns (By_Index [-1, 0, 1]) reorder=True
column1 = table.at "foo_1"
@ -94,11 +94,11 @@ spec prefix table_builder test_selection pending=Nothing =
table_2 . at "foo" . to_vector . should_equal [1,2,3]
Test.specify "should correctly handle regex matching" <|
expect_column_names ["foo"] <| table.select_columns (By_Name ["foo"] Regex_Matcher_Data)
expect_column_names ["ab.+123", "abcd123"] <| table.select_columns (By_Name ["a.*"] Regex_Matcher_Data)
expect_column_names ["ab.+123", "abcd123"] <| table.select_columns (By_Name ["ab.+123"] Regex_Matcher_Data)
expect_column_names ["foo"] <| table.select_columns (By_Name ["foo"] (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive))
expect_column_names ["ab.+123", "abcd123"] <| table.select_columns (By_Name ["a.*"] (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive))
expect_column_names ["ab.+123", "abcd123"] <| table.select_columns (By_Name ["ab.+123"] (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive))
expect_column_names ["ab.+123"] <| table.select_columns (By_Name ["ab.+123"])
expect_column_names ["abcd123"] <| table.select_columns (By_Name ["abcd123"] Regex_Matcher_Data)
expect_column_names ["abcd123"] <| table.select_columns (By_Name ["abcd123"] (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive))
Test.specify "should allow negative indices" <|
expect_column_names ["foo", "bar", "foo_2"] <| table.select_columns (By_Index [-3, 0, 1])
@ -110,11 +110,11 @@ spec prefix table_builder test_selection pending=Nothing =
col2 = ["bar", [4,5,6]]
col3 = ["Bar", [7,8,9]]
table_builder [col1, col2, col3]
expect_column_names ["bar", "Bar"] <| table.select_columns (By_Name ["bar"] (Text_Matcher_Data Case_Insensitive_Data))
expect_column_names ["bar", "Bar"] <| table.select_columns (By_Name ["bar"] Text_Matcher.Case_Insensitive)
Test.specify "should correctly handle regexes matching multiple names" <|
expect_column_names ["foo", "bar", "foo_1", "foo_2"] <| table.select_columns (By_Name ["b.*", "f.+"] Regex_Matcher_Data)
expect_column_names ["bar", "foo", "foo_1", "foo_2"] <| table.select_columns (By_Name ["b.*", "f.+"] Regex_Matcher_Data) reorder=True
expect_column_names ["foo", "bar", "foo_1", "foo_2"] <| table.select_columns (By_Name ["b.*", "f.+"] (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive))
expect_column_names ["bar", "foo", "foo_1", "foo_2"] <| table.select_columns (By_Name ["b.*", "f.+"] (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive)) reorder=True
Test.specify "should correctly handle problems: out of bounds indices" <|
selector = By_Index [1, 0, 100, -200, 300]
@ -145,14 +145,14 @@ spec prefix table_builder test_selection pending=Nothing =
Problems.test_problem_handling action problems tester
Test.specify "should correctly handle problems: duplicate matches due to case insensitivity" pending="TODO needs fixing" <|
selector = By_Name ["FOO", "foo"] (Text_Matcher_Data case_sensitive=Case_Insensitive_Data)
selector = By_Name ["FOO", "foo"] Text_Matcher.Case_Insensitive
action = table.select_columns selector on_problems=_
tester = expect_column_names ["foo"]
problems = [Duplicate_Column_Selectors_Data ["foo"]]
Problems.test_problem_handling action problems tester
Test.specify "should correctly handle problems: duplicate matches due to case insensitivity" pending="TODO needs fixing" <|
selector = By_Name.new ["FOO", "foo"] (Text_Matcher_Data case_sensitive=Case_Insensitive_Data)
selector = By_Name.new ["FOO", "foo"] Text_Matcher.Case_Insensitive
action = table.select_columns selector on_problems=_
tester = expect_column_names ["foo"]
problems = [Duplicate_Column_Selectors_Data ["foo"]]
@ -208,7 +208,7 @@ spec prefix table_builder test_selection pending=Nothing =
Test.group prefix+"Table.remove_columns" pending=pending <|
Test.specify "should work as shown in the doc examples" <|
expect_column_names ["Baz", "foo_1", "foo_2", "ab.+123", "abcd123"] <| table.remove_columns (By_Name ["bar", "foo"])
expect_column_names ["foo", "ab.+123", "abcd123"] <| table.remove_columns (By_Name ["foo.+", "b.*"] (Regex_Matcher_Data case_sensitive=Case_Insensitive_Data))
expect_column_names ["foo", "ab.+123", "abcd123"] <| table.remove_columns (By_Name ["foo.+", "b.*"] (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Insensitive))
expect_column_names ["Baz", "foo_1", "foo_2", "ab.+123"] <| table.remove_columns (By_Index [-1, 0, 1])
column1 = table.at "foo_1"
@ -217,12 +217,12 @@ spec prefix table_builder test_selection pending=Nothing =
Test.specify "should correctly handle regex matching" <|
last_ones = table.columns.tail.map .name
expect_column_names last_ones <| table.remove_columns (By_Name ["foo"] Regex_Matcher_Data)
expect_column_names last_ones <| table.remove_columns (By_Name ["foo"] (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive))
first_ones = ["foo", "bar", "Baz", "foo_1", "foo_2"]
expect_column_names first_ones <| table.remove_columns (By_Name ["a.*"] Regex_Matcher_Data)
expect_column_names first_ones <| table.remove_columns (By_Name ["ab.+123"] Regex_Matcher_Data)
expect_column_names first_ones <| table.remove_columns (By_Name ["a.*"] (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive))
expect_column_names first_ones <| table.remove_columns (By_Name ["ab.+123"] (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive))
expect_column_names first_ones+["abcd123"] <| table.remove_columns (By_Name ["ab.+123"])
expect_column_names first_ones+["ab.+123"] <| table.remove_columns (By_Name ["abcd123"] Regex_Matcher_Data)
expect_column_names first_ones+["ab.+123"] <| table.remove_columns (By_Name ["abcd123"] (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive))
Test.specify "should allow negative indices" <|
expect_column_names ["Baz", "foo_1", "ab.+123"] <| table.remove_columns (By_Index [-1, -3, 0, 1])
@ -234,10 +234,10 @@ spec prefix table_builder test_selection pending=Nothing =
col2 = ["bar", [4,5,6]]
col3 = ["Bar", [7,8,9]]
table_builder [col1, col2, col3]
expect_column_names ["foo"] <| table.remove_columns (By_Name ["bar"] (Text_Matcher_Data Case_Insensitive_Data))
expect_column_names ["foo"] <| table.remove_columns (By_Name ["bar"] Text_Matcher.Case_Insensitive)
Test.specify "should correctly handle regexes matching multiple names" <|
expect_column_names ["Baz", "ab.+123", "abcd123"] <| table.remove_columns (By_Name ["b.*", "f.+"] Regex_Matcher_Data)
expect_column_names ["Baz", "ab.+123", "abcd123"] <| table.remove_columns (By_Name ["b.*", "f.+"] (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive))
Test.specify "should correctly handle problems: out of bounds indices" <|
selector = By_Index [1, 0, 100, -200, 300]
@ -268,14 +268,14 @@ spec prefix table_builder test_selection pending=Nothing =
Problems.test_problem_handling action problems tester
Test.specify "should correctly handle problems: duplicate matches due to case insensitivity" pending="TODO needs fixing" <|
selector = By_Name ["FOO", "foo"] (Text_Matcher_Data case_sensitive=Case_Insensitive_Data)
selector = By_Name ["FOO", "foo"] Text_Matcher.Case_Insensitive
action = table.remove_columns selector on_problems=_
tester = expect_column_names ["bar", "Baz", "foo_1", "foo_2", "ab.+123", "abcd123"]
problems = [Duplicate_Column_Selectors_Data ["foo"]]
Problems.test_problem_handling action problems tester
Test.specify "should correctly handle problems: duplicate matches due to case insensitivity" pending="TODO needs fixing" <|
selector = By_Name.new ["FOO", "foo"] (Text_Matcher_Data case_sensitive=Case_Insensitive_Data)
selector = By_Name.new ["FOO", "foo"] Text_Matcher.Case_Insensitive
action = table.remove_columns selector on_problems=_
tester = expect_column_names ["bar", "Baz", "foo_1", "foo_2", "ab.+123", "abcd123"]
problems = [Duplicate_Column_Selectors_Data ["foo"]]
@ -310,14 +310,14 @@ spec prefix table_builder test_selection pending=Nothing =
Problems.test_problem_handling action problems tester
Test.specify "should correctly handle problems: no columns in the output" <|
selector = By_Name [".*"] Regex_Matcher_Data
selector = By_Name [".*"] (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive)
action = table.remove_columns selector on_problems=_
tester = expect_column_names []
problems = [No_Output_Columns]
Problems.test_problem_handling action problems tester
Test.specify "should correctly handle multiple problems" <|
selector = By_Name [".*", "hmmm"] Regex_Matcher_Data
selector = By_Name [".*", "hmmm"] (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive)
action = table.remove_columns selector on_problems=_
tester = expect_column_names []
problems = [Missing_Input_Columns_Data ["hmmm"], No_Output_Columns]
@ -331,7 +331,7 @@ spec prefix table_builder test_selection pending=Nothing =
Test.group prefix+"Table.reorder_columns" pending=pending <|
Test.specify "should work as shown in the doc examples" <|
expect_column_names ["bar", "Baz", "foo_1", "foo_2", "ab.+123", "abcd123", "foo"] <| table.reorder_columns (By_Name ["foo"]) position=After_Other_Columns
expect_column_names ["foo_1", "foo_2", "bar", "Baz", "foo", "ab.+123", "abcd123"] <| table.reorder_columns (By_Name ["foo.+", "b.*"] (Regex_Matcher_Data case_sensitive=Case_Insensitive_Data))
expect_column_names ["foo_1", "foo_2", "bar", "Baz", "foo", "ab.+123", "abcd123"] <| table.reorder_columns (By_Name ["foo.+", "b.*"] (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Insensitive))
expect_column_names ["bar", "foo", "Baz", "foo_1", "foo_2", "ab.+123", "abcd123"] <| table.reorder_columns (By_Index [1, 0]) position=Before_Other_Columns
expect_column_names ["bar", "Baz", "foo_1", "foo_2", "ab.+123", "abcd123", "foo"] <| table.reorder_columns (By_Index [0]) position=After_Other_Columns
@ -340,12 +340,12 @@ spec prefix table_builder test_selection pending=Nothing =
expect_column_names ["foo_1", "Baz", "foo", "bar", "foo_2", "ab.+123", "abcd123"] <| table.reorder_columns (By_Column [column1, column2])
Test.specify "should correctly handle regex matching" <|
expect_column_names ["bar", "Baz", "foo_1", "foo_2", "ab.+123", "abcd123", "foo"] <| table.reorder_columns (By_Name ["foo"] Regex_Matcher_Data) position=After_Other_Columns
expect_column_names ["bar", "Baz", "foo_1", "foo_2", "ab.+123", "abcd123", "foo"] <| table.reorder_columns (By_Name ["foo"] (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive)) position=After_Other_Columns
rest = ["foo", "bar", "Baz", "foo_1", "foo_2"]
expect_column_names ["ab.+123", "abcd123"]+rest <| table.reorder_columns (By_Name ["a.*"] Regex_Matcher_Data)
expect_column_names ["ab.+123", "abcd123"]+rest <| table.reorder_columns (By_Name ["ab.+123"] Regex_Matcher_Data)
expect_column_names ["ab.+123", "abcd123"]+rest <| table.reorder_columns (By_Name ["a.*"] (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive))
expect_column_names ["ab.+123", "abcd123"]+rest <| table.reorder_columns (By_Name ["ab.+123"] (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive))
expect_column_names ["ab.+123"]+rest+["abcd123"] <| table.reorder_columns (By_Name ["ab.+123"])
expect_column_names ["abcd123"]+rest+["ab.+123"] <| table.reorder_columns (By_Name ["abcd123"] Regex_Matcher_Data)
expect_column_names ["abcd123"]+rest+["ab.+123"] <| table.reorder_columns (By_Name ["abcd123"] (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive))
Test.specify "should allow negative indices" <|
expect_column_names ["abcd123", "foo_2", "foo", "bar", "Baz", "foo_1", "ab.+123"] <| table.reorder_columns (By_Index [-1, -3, 0, 1])
@ -357,10 +357,10 @@ spec prefix table_builder test_selection pending=Nothing =
col2 = ["bar", [4,5,6]]
col3 = ["Bar", [7,8,9]]
table_builder [col1, col2, col3]
expect_column_names ["bar", "Bar", "foo"] <| table.reorder_columns (By_Name ["bar"] (Text_Matcher_Data Case_Insensitive_Data))
expect_column_names ["bar", "Bar", "foo"] <| table.reorder_columns (By_Name ["bar"] Text_Matcher.Case_Insensitive)
Test.specify "should correctly handle regexes matching multiple names" <|
expect_column_names ["bar", "foo", "foo_1", "foo_2", "Baz", "ab.+123", "abcd123"] <| table.reorder_columns (By_Name ["b.*", "f.+"] Regex_Matcher_Data)
expect_column_names ["bar", "foo", "foo_1", "foo_2", "Baz", "ab.+123", "abcd123"] <| table.reorder_columns (By_Name ["b.*", "f.+"] (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive))
Test.specify "should correctly handle problems: out of bounds indices" <|
selector = By_Index [1, 0, 100, -200, 300]
@ -440,17 +440,17 @@ spec prefix table_builder test_selection pending=Nothing =
expect_column_names ["Foo_2", "bar", "foo_001", "foo_1", "foo_100", "foo_21", "foo_3"] sorted
sorted.columns.first.to_vector . should_equal [10,11,12]
expect_column_names ["bar", "foo_001", "foo_1", "Foo_2", "foo_3", "foo_21", "foo_100"] <| table.sort_columns text_ordering=(Text_Ordering_Data sort_digits_as_numbers=True case_sensitive=Case_Insensitive_Data)
expect_column_names ["bar", "foo_001", "foo_1", "Foo_2", "foo_3", "foo_21", "foo_100"] <| table.sort_columns text_ordering=(Text_Ordering.Case_Insensitive sort_digits_as_numbers=True)
expect_column_names ["foo_3", "foo_21", "foo_100", "foo_1", "foo_001", "bar", "Foo_2"] <| table.sort_columns Sort_Direction.Descending
Test.specify "should correctly handle case-insensitive sorting" <|
expect_column_names ["bar", "foo_001", "foo_1", "foo_100", "Foo_2", "foo_21", "foo_3"] <| table.sort_columns text_ordering=(Text_Ordering_Data case_sensitive=Case_Insensitive_Data)
expect_column_names ["bar", "foo_001", "foo_1", "foo_100", "Foo_2", "foo_21", "foo_3"] <| table.sort_columns text_ordering=(Text_Ordering.Case_Insensitive)
Test.specify "should correctly handle natural order sorting" <|
expect_column_names ["Foo_2", "bar", "foo_001", "foo_1", "foo_3", "foo_21", "foo_100"] <| table.sort_columns text_ordering=(Text_Ordering_Data sort_digits_as_numbers=True)
expect_column_names ["Foo_2", "bar", "foo_001", "foo_1", "foo_3", "foo_21", "foo_100"] <| table.sort_columns text_ordering=(Text_Ordering.Default sort_digits_as_numbers=True)
Test.specify "should correctly handle various combinations of options" <|
expect_column_names ["foo_100", "foo_21", "foo_3", "Foo_2", "foo_1", "foo_001", "bar"] <| table.sort_columns direction=Sort_Direction.Descending text_ordering=(Text_Ordering_Data sort_digits_as_numbers=True case_sensitive=Case_Insensitive_Data)
expect_column_names ["foo_100", "foo_21", "foo_3", "Foo_2", "foo_1", "foo_001", "bar"] <| table.sort_columns direction=Sort_Direction.Descending text_ordering=(Text_Ordering.Case_Insensitive sort_digits_as_numbers=True)
Test.group prefix+"Table.rename_columns" pending=pending <|
table =
@ -477,22 +477,22 @@ spec prefix table_builder test_selection pending=Nothing =
Test.specify "should work by name" <|
map = Map.from_vector [["alpha", "FirstColumn"], ["delta", "Another"]]
expect_column_names ["FirstColumn", "beta", "gamma", "Another"] <|
table.rename_columns (Column_Name_Mapping.By_Name map (Text_Matcher_Data True))
table.rename_columns (Column_Name_Mapping.By_Name map (Text_Matcher.Case_Sensitive))
Test.specify "should work by name case-insensitively" <|
map = Map.from_vector [["ALPHA", "FirstColumn"], ["DELTA", "Another"]]
expect_column_names ["FirstColumn", "beta", "gamma", "Another"] <|
table.rename_columns (Column_Name_Mapping.By_Name map (Text_Matcher_Data Case_Insensitive_Data))
table.rename_columns (Column_Name_Mapping.By_Name map Text_Matcher.Case_Insensitive)
Test.specify "should work by name using regex" <|
map = Map.from_vector [["a.*", "FirstColumn"]]
expect_column_names ["FirstColumn", "beta", "gamma", "delta"] <|
table.rename_columns (Column_Name_Mapping.By_Name map Regex_Matcher_Data)
table.rename_columns (Column_Name_Mapping.By_Name map (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive))
Test.specify "should work by name using regex substitution" <|
map = Map.from_vector [["a(.*)", "$1"]]
expect_column_names ["lpha", "beta", "gamma", "delta"] <|
table.rename_columns (Column_Name_Mapping.By_Name map Regex_Matcher_Data)
table.rename_columns (Column_Name_Mapping.By_Name map (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive))
Test.specify "should work by column" <|
vec = [[table.at "alpha", "FirstColumn"], [table.at "delta", "Another"]]
@ -584,7 +584,7 @@ spec prefix table_builder test_selection pending=Nothing =
t2.at "alpha" . to_vector . should_equal [1, 3, 0, 2]
Test.specify "should correctly handle regexes matching multiple names" <|
t1 = table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name ".*ta" Sort_Direction.Descending] Regex_Matcher_Data)
t1 = table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name ".*ta" Sort_Direction.Descending] (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive))
t1.at "beta" . to_vector . should_equal ["b", "b", "a", "a"]
t1.at "delta" . to_vector . should_equal ["a1", "a03", "a2", "a10"]
t1.at "gamma" . to_vector . should_equal [2, 4, 3, 1]
@ -627,7 +627,7 @@ spec prefix table_builder test_selection pending=Nothing =
Problems.test_problem_handling action problems tester
Test.specify "should correctly handle problems: duplicate matches due to case insensitivity" <|
selector = Sort_Column_Selector.By_Name [Sort_Column.Name "ALPHA", Sort_Column.Name "alpha" Sort_Direction.Descending] (Text_Matcher_Data case_sensitive=Case_Insensitive_Data)
selector = Sort_Column_Selector.By_Name [Sort_Column.Name "ALPHA", Sort_Column.Name "alpha" Sort_Direction.Descending] Text_Matcher.Case_Insensitive
action = table.order_by selector on_problems=_
tester table =
table.at "alpha" . to_vector . should_equal [0, 1, 2, 3]
@ -740,45 +740,45 @@ spec prefix table_builder test_selection pending=Nothing =
t1.at "alpha" . to_vector . should_equal [2, 1, 0, 3]
Test.specify "should support natural ordering" pending=(if test_selection.natural_ordering.not then "Natural ordering is not supported.") <|
t1 = table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "delta"]) text_ordering=(Text_Ordering_Data sort_digits_as_numbers=True)
t1 = table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "delta"]) text_ordering=(Text_Ordering.Default sort_digits_as_numbers=True)
t1.at "delta" . to_vector . should_equal ["a1", "a2", "a03", "a10"]
t1.at "alpha" . to_vector . should_equal [2, 1, 0, 3]
t2 = table.order_by (Sort_Column_Selector.By_Name ["delta"]) text_ordering=(Text_Ordering_Data sort_digits_as_numbers=False)
t2 = table.order_by (Sort_Column_Selector.By_Name ["delta"]) text_ordering=(Text_Ordering.Default sort_digits_as_numbers=False)
t2.at "delta" . to_vector . should_equal ["a03", "a1", "a10", "a2"]
t2.at "alpha" . to_vector . should_equal [0, 2, 3, 1]
Test.specify "should support case insensitive ordering" pending=(if test_selection.case_insensitive_ordering.not then "Case insensitive ordering is not supported.") <|
t1 = table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "eta"]) text_ordering=(Text_Ordering_Data case_sensitive=Case_Insensitive_Data)
t1 = table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "eta"]) text_ordering=(Text_Ordering.Case_Insensitive)
expected = case test_selection.case_insensitive_ascii_only of
True -> ["Aleph", "alpha", "Beta", "bądź"]
False -> ["Aleph", "alpha", "bądź", "Beta"]
t1.at "eta" . to_vector . should_equal expected
t2 = table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "eta"]) text_ordering=(Text_Ordering_Data case_sensitive=True)
t2 = table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "eta"]) text_ordering=(Text_Ordering.Case_Sensitive)
t2.at "eta" . to_vector . should_equal ["Aleph", "Beta", "alpha", "bądź"]
t3 = table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "psi"]) text_ordering=(Text_Ordering_Data case_sensitive=Case_Insensitive_Data)
t3 = table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "psi"]) text_ordering=(Text_Ordering.Case_Insensitive)
t3.at "psi" . to_vector . should_equal [Nothing, "c01", "c10", "C2"]
t4 = table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "psi" Sort_Direction.Descending]) text_ordering=(Text_Ordering_Data case_sensitive=True)
t4 = table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "psi" Sort_Direction.Descending]) text_ordering=(Text_Ordering.Case_Sensitive)
t4.at "psi" . to_vector . should_equal ["c10", "c01", "C2", Nothing]
Test.specify "should support natural and case insensitive ordering at the same time" pending=(if (test_selection.natural_ordering.not || test_selection.case_insensitive_ordering.not) then "Natural ordering or case sensitive ordering is not supported.") <|
t1 = table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "psi"]) text_ordering=(Text_Ordering_Data sort_digits_as_numbers=True case_sensitive=Case_Insensitive_Data)
t1 = table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "psi"]) text_ordering=(Text_Ordering.Case_Insensitive sort_digits_as_numbers=True)
t1.at "psi" . to_vector . should_equal [Nothing, "c01", "C2", "c10"]
t2 = table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "psi"]) text_ordering=(Text_Ordering_Data sort_digits_as_numbers=True)
t2 = table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "psi"]) text_ordering=(Text_Ordering.Default sort_digits_as_numbers=True)
t2.at "psi" . to_vector . should_equal [Nothing, "C2", "c01", "c10"]
t3 = table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "psi"]) text_ordering=(Text_Ordering_Data case_sensitive=Case_Insensitive_Data)
t3 = table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "psi"]) text_ordering=(Text_Ordering.Case_Insensitive)
t3.at "psi" . to_vector . should_equal [Nothing, "c01", "c10", "C2"]
t4 = table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "psi"])
t4.at "psi" . to_vector . should_equal [Nothing, "C2", "c01", "c10"]
Test.specify "text ordering settings should not affect numeric columns" <|
ordering = Text_Ordering_Data sort_digits_as_numbers=True case_sensitive=Case_Insensitive_Data
ordering = Text_Ordering.Case_Insensitive sort_digits_as_numbers=True
t1 = table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "alpha"]) text_ordering=ordering
t1.at "alpha" . to_vector . should_equal [0, 1, 2, 3]
t1.at "gamma" . to_vector . should_equal [4, 3, 2, 1]

View File

@ -780,12 +780,12 @@ spec =
d1.at "X" . to_vector . should_equal ['A', 'a', 'enso', 'śledź', 'Enso']
d1.at "Y" . to_vector . should_equal [1, 2, 3, 4, 5]
d2 = t1.distinct (By_Name ["X"]) case_sensitive=Case_Insensitive_Data on_problems=Report_Error
d2 = t1.distinct (By_Name ["X"]) case_sensitivity=Case_Sensitivity.Insensitive on_problems=Report_Error
d2.at "X" . to_vector . should_equal ['A', 'enso', 'śledź']
d2.at "Y" . to_vector . should_equal [1, 3, 4]
t2 = Table.new [["X", ["łąka", "STRASSE", "Straße", "ffi", "ŁĄka", "ffi"]]]
t2.distinct case_sensitive=Case_Insensitive_Data . at "X" . to_vector . should_equal ["łąka", "STRASSE", "ffi"]
t2.distinct case_sensitivity=Case_Sensitivity.Insensitive . at "X" . to_vector . should_equal ["łąka", "STRASSE", "ffi"]
Test.specify "should report a warning if the key contains floating point values" <|
t1 = Table.new [["X", [3.0, 1.0, 2.0, 2.0, 1.0]]]

View File

@ -22,7 +22,7 @@ type No_Ord
spec = Test.group "Object Comparator" <|
handle_classcast = Panic.catch ClassCastException handler=(_ -> Error.throw Vector.Incomparable_Values_Error)
default_comparator a b = handle_classcast <| Comparator.new.compare a b
case_insensitive a b = handle_classcast <| Comparator.for_text_ordering (Text_Ordering_Data False Case_Insensitive_Data) . compare a b
case_insensitive a b = handle_classcast <| Comparator.for_text_ordering Text_Ordering.Case_Insensitive . compare a b
Test.specify "can compare numbers" <|
((default_comparator 1 2) < 0) . should_equal True

View File

@ -3,7 +3,7 @@ from Standard.Base import all
import Standard.Test
spec = Test.group "Natural Order" <|
case_insensitive_compare a b = Natural_Order.compare a b Case_Insensitive_Data
case_insensitive_compare a b = Natural_Order.compare a b Case_Sensitivity.Insensitive
Test.specify "should behave as shown in examples" <|
Natural_Order.compare "a2" "a100" . should_equal Ordering.Less

View File

@ -7,70 +7,70 @@ type Foo_Error
spec = Test.group 'Matching Helper' <|
Test.specify 'should match a single name with a single Text_Matcher criterion' <|
Text_Matcher_Data.match_single_criterion "foo" "foo" . should_be_true
Text_Matcher_Data.match_single_criterion "foobar" "foo" . should_be_false
Text_Matcher_Data.match_single_criterion "foo" "f.*" . should_be_false
Text_Matcher_Data.match_single_criterion "foo" "Foo" . should_be_false
Text_Matcher.Case_Sensitive.match_single_criterion "foo" "foo" . should_be_true
Text_Matcher.Case_Sensitive.match_single_criterion "foobar" "foo" . should_be_false
Text_Matcher.Case_Sensitive.match_single_criterion "foo" "f.*" . should_be_false
Text_Matcher.Case_Sensitive.match_single_criterion "foo" "Foo" . should_be_false
Test.specify 'should correctly handle Unicode folding with Text_Matcher_Data matching' <|
Text_Matcher_Data.match_single_criterion '\u00E9' '\u0065\u{301}' . should_be_true
Text_Matcher_Data.match_single_criterion 'é' '\u00E9' . should_be_true
Text_Matcher_Data.match_single_criterion 'é' 'ę' . should_be_false
Test.specify 'should correctly handle Unicode folding with Text_Matcher matching' <|
Text_Matcher.Case_Sensitive.match_single_criterion '\u00E9' '\u0065\u{301}' . should_be_true
Text_Matcher.Case_Sensitive.match_single_criterion 'é' '\u00E9' . should_be_true
Text_Matcher.Case_Sensitive.match_single_criterion 'é' 'ę' . should_be_false
Test.specify 'should match a single name with a single regex criterion' <|
Regex_Matcher_Data.match_single_criterion "foo" "foo" . should_be_true
Regex_Matcher_Data.match_single_criterion "foobar" "foo" . should_be_false
Regex_Matcher_Data.match_single_criterion "foo" "f.*" . should_be_true
Regex_Matcher_Data.match_single_criterion "foo" "foo.*" . should_be_true
Regex_Matcher_Data.match_single_criterion "foo" "F.*" . should_be_false
(Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive).match_single_criterion "foo" "foo" . should_be_true
(Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive).match_single_criterion "foobar" "foo" . should_be_false
(Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive).match_single_criterion "foo" "f.*" . should_be_true
(Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive).match_single_criterion "foo" "foo.*" . should_be_true
(Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive).match_single_criterion "foo" "F.*" . should_be_false
Test.specify 'should support case-insensitive matching' <|
(Regex_Matcher_Data case_sensitive=Case_Insensitive_Data).match_single_criterion "foo" "F.*" . should_be_true
(Text_Matcher_Data case_sensitive=Case_Insensitive_Data).match_single_criterion "foO" "FOo" . should_be_true
(Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Insensitive).match_single_criterion "foo" "F.*" . should_be_true
Text_Matcher.Case_Insensitive.match_single_criterion "foO" "FOo" . should_be_true
(Regex_Matcher_Data case_sensitive=Case_Insensitive_Data).match_single_criterion "foo" "fF.*" . should_be_false
(Text_Matcher_Data case_sensitive=Case_Insensitive_Data).match_single_criterion "foo" "Foos" . should_be_false
(Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Insensitive).match_single_criterion "foo" "fF.*" . should_be_false
Text_Matcher.Case_Insensitive.match_single_criterion "foo" "Foos" . should_be_false
# Small beta is equal to capital 'beta' which looks the same as capital 'b' but is a different symbol.
(Text_Matcher_Data case_sensitive=Case_Insensitive_Data).match_single_criterion "β" "Β" . should_be_true
(Text_Matcher_Data case_sensitive=Case_Insensitive_Data).match_single_criterion "β" "B" . should_be_false
Text_Matcher.Case_Insensitive.match_single_criterion "β" "Β" . should_be_true
Text_Matcher.Case_Insensitive.match_single_criterion "β" "B" . should_be_false
Test.specify 'should match a list of names with a list of criteria, correctly handling reordering' <|
Text_Matcher_Data.match_criteria ["foo", "bar", "baz"] ["baz", "foo"] reorder=True . should_equal ["baz", "foo"]
Text_Matcher_Data.match_criteria ["foo", "bar", "baz"] ["baz", "foo"] reorder=False . should_equal ["foo", "baz"]
Text_Matcher.Case_Sensitive.match_criteria ["foo", "bar", "baz"] ["baz", "foo"] reorder=True . should_equal ["baz", "foo"]
Text_Matcher.Case_Sensitive.match_criteria ["foo", "bar", "baz"] ["baz", "foo"] reorder=False . should_equal ["foo", "baz"]
Test.specify 'should allow multiple matches to a single criterion (Regex)' <|
Regex_Matcher_Data.match_criteria ["foo", "bar", "baz", "quux"] ["b.*"] reorder=True . should_equal ["bar", "baz"]
Regex_Matcher_Data.match_criteria ["foo", "bar", "baz", "quux"] ["b.*", "foo"] reorder=False . should_equal ["foo", "bar", "baz"]
(Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive).match_criteria ["foo", "bar", "baz", "quux"] ["b.*"] reorder=True . should_equal ["bar", "baz"]
(Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive).match_criteria ["foo", "bar", "baz", "quux"] ["b.*", "foo"] reorder=False . should_equal ["foo", "bar", "baz"]
Test.specify 'should include the object only with the first criterion that matched it, avoiding duplication' <|
Regex_Matcher_Data.match_criteria ["foo", "bar", "baz", "zap"] [".*z.*", "b.*"] reorder=True . should_equal ["baz", "zap", "bar"]
Regex_Matcher_Data.match_criteria ["foo", "bar", "baz", "zap"] [".*z.*", "b.*"] reorder=False . should_equal ["bar", "baz", "zap"]
(Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive).match_criteria ["foo", "bar", "baz", "zap"] [".*z.*", "b.*"] reorder=True . should_equal ["baz", "zap", "bar"]
(Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive).match_criteria ["foo", "bar", "baz", "zap"] [".*z.*", "b.*"] reorder=False . should_equal ["bar", "baz", "zap"]
Test.specify 'should correctly handle criteria which did not match anything' <|
action = Text_Matcher_Data.match_criteria ["foo", "bar", "baz"] ["baz", "unknown_column"] reorder=True on_problems=_
action = Text_Matcher.Case_Sensitive.match_criteria ["foo", "bar", "baz"] ["baz", "unknown_column"] reorder=True on_problems=_
tester = _.should_equal ["baz"]
problems = [No_Matches_Found_Data ["unknown_column"]]
Problems.test_problem_handling action problems tester
action_2 = Text_Matcher_Data.match_criteria ["foo", "bar", "baz"] ["baz", "unknown_column_1", "unknown_column_2"] reorder=False on_problems=_
action_2 = Text_Matcher.Case_Sensitive.match_criteria ["foo", "bar", "baz"] ["baz", "unknown_column_1", "unknown_column_2"] reorder=False on_problems=_
problems_2 = [No_Matches_Found_Data ["unknown_column_1", "unknown_column_2"]]
Problems.test_problem_handling action_2 problems_2 tester
Test.specify 'should correctly work with complex object using a function extracting their names' <|
pairs = [Pair_Data "foo" 42, Pair_Data "bar" 33, Pair_Data "baz" 10, Pair_Data "foo" 0, Pair_Data 10 10]
selected = [Pair_Data "bar" 33, Pair_Data "foo" 42, Pair_Data "foo" 0]
Text_Matcher_Data.match_criteria pairs ["bar", "foo"] reorder=True name_mapper=_.first . should_equal selected
Text_Matcher.Case_Sensitive.match_criteria pairs ["bar", "foo"] reorder=True name_mapper=_.first . should_equal selected
Text_Matcher_Data.match_criteria [1, 2, 3] ["2"] name_mapper=_.to_text . should_equal [2]
Text_Matcher.Case_Sensitive.match_criteria [1, 2, 3] ["2"] name_mapper=_.to_text . should_equal [2]
Test.specify 'should correctly forward errors' <|
Text_Matcher_Data.match_criteria (Error.throw Foo_Error) [] . should_fail_with Foo_Error
Text_Matcher_Data.match_criteria [] (Error.throw Foo_Error) . should_fail_with Foo_Error
Text_Matcher.Case_Sensitive.match_criteria (Error.throw Foo_Error) [] . should_fail_with Foo_Error
Text_Matcher.Case_Sensitive.match_criteria [] (Error.throw Foo_Error) . should_fail_with Foo_Error
(Error.throw Foo_Error).match_criteria [] [] . should_fail_with Foo_Error
Text_Matcher_Data.match_criteria [1, 2, 3] ["2"] name_mapper=(x-> if x == 3 then Error.throw Foo_Error else x.to_text) . should_fail_with Foo_Error
Text_Matcher.Case_Sensitive.match_criteria [1, 2, 3] ["2"] name_mapper=(x-> if x == 3 then Error.throw Foo_Error else x.to_text) . should_fail_with Foo_Error
Test.expect_panic_with matcher=No_Such_Method_Error_Data <|
Text_Matcher_Data.match_criteria ["a"] ["a"] name_mapper=_.nonexistent_function
Text_Matcher.Case_Sensitive.match_criteria ["a"] ["a"] name_mapper=_.nonexistent_function
main = Test.Suite.run_main spec

View File

@ -206,7 +206,7 @@ spec =
'abc'.split '' . should_fail_with Illegal_Argument_Error_Data
Test.specify "should be able to split the text on arbitrary text sequence, case-insensitively" <|
matcher = Text_Matcher_Data Case_Insensitive_Data
matcher = Text_Matcher.Case_Insensitive
"AbCdABCDabDCba" . split "ab" matcher . should_equal ["", "Cd", "CD", "DCba"]
"abc".split "d" matcher . should_equal ["abc"]
"AAA".split "a" matcher . should_equal ["", "", "", ""]
@ -216,20 +216,20 @@ spec =
'abc'.split '' matcher . should_fail_with Illegal_Argument_Error_Data
Test.specify "should be able to split the text on Regex patterns" <|
"cababdabe" . split "ab" Regex_Matcher_Data . should_equal ["c", "", "d", "e"]
"cababdabe" . split "(ab)+" Regex_Matcher_Data . should_equal ["c", "d", "e"]
"abc" . split "[a-z]" Regex_Matcher_Data . should_equal ["", "", "", ""]
"abc--def==>ghi".split "[-=>]+" Regex_Matcher_Data == ["abc", "def", "ghi"]
"abc".split "." Regex_Matcher_Data . should_equal ["", "", "", ""]
"abc".split "d" Regex_Matcher_Data . should_equal ["abc"]
".a.".split "\." Regex_Matcher_Data . should_equal ["", "a", ""]
"".split "a" Regex_Matcher_Data . should_equal [""]
'aśbs\u{301}c'.split 'ś' Regex_Matcher_Data . should_equal ['a', 'b', 'c']
'abc'.split '' Regex_Matcher_Data . should_fail_with Illegal_Argument_Error_Data
"cababdabe" . split "ab" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_equal ["c", "", "d", "e"]
"cababdabe" . split "(ab)+" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_equal ["c", "d", "e"]
"abc" . split "[a-z]" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_equal ["", "", "", ""]
"abc--def==>ghi".split "[-=>]+" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) == ["abc", "def", "ghi"]
"abc".split "." (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_equal ["", "", "", ""]
"abc".split "d" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_equal ["abc"]
".a.".split "\." (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_equal ["", "a", ""]
"".split "a" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_equal [""]
'aśbs\u{301}c'.split 'ś' (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_equal ['a', 'b', 'c']
'abc'.split '' (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_fail_with Illegal_Argument_Error_Data
Test.specify "should be able to split the text on UTF-8 whitespace" <|
utf_8_whitespace.split "\s+" Regex_Matcher_Data . should_equal utf_8_whitespace_split
'abc def\tghi'.split '\\s+' Regex_Matcher_Data . should_equal ["abc", "def", "ghi"]
utf_8_whitespace.split "\s+" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_equal utf_8_whitespace_split
'abc def\tghi'.split '\\s+' (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_equal ["abc", "def", "ghi"]
Test.specify "should convert any type to text automatically and using provided methods" <|
t = Auto.Value (Manual.Value 123) . to_text
@ -753,25 +753,25 @@ spec =
"Hello!".contains "Lo" . should_be_false
Test.specify "should allow for case-insensitive contains checks" <|
"Hello!".contains 'LO' (Text_Matcher_Data Case_Insensitive_Data) . should_be_true
"FoObar" . contains "foo" (Text_Matcher_Data Case_Insensitive_Data) . should_be_true
"aaaIAAA" . contains "i" (Text_Matcher_Data Case_Insensitive_Data) . should_be_true
"Foo" . contains "bar" (Text_Matcher_Data Case_Insensitive_Data) . should_be_false
"Ściana" . contains "ś" (Text_Matcher_Data Case_Insensitive_Data) . should_be_true
"Ściana" . contains "s" (Text_Matcher_Data Case_Insensitive_Data) . should_be_false
"Hello!".contains 'LO' Text_Matcher.Case_Insensitive . should_be_true
"FoObar" . contains "foo" Text_Matcher.Case_Insensitive . should_be_true
"aaaIAAA" . contains "i" Text_Matcher.Case_Insensitive . should_be_true
"Foo" . contains "bar" Text_Matcher.Case_Insensitive . should_be_false
"Ściana" . contains "ś" Text_Matcher.Case_Insensitive . should_be_true
"Ściana" . contains "s" Text_Matcher.Case_Insensitive . should_be_false
"Straße" . contains "ss" . should_be_false
"Strasse" . contains "ß" . should_be_false
"Straße" . contains "ss" (Text_Matcher_Data Case_Insensitive_Data) . should_be_true
"Strasse" . contains "ß" (Text_Matcher_Data Case_Insensitive_Data) . should_be_true
"Straße" . contains "ss" Text_Matcher.Case_Insensitive . should_be_true
"Strasse" . contains "ß" Text_Matcher.Case_Insensitive . should_be_true
Test.specify "should allow for Regex contains checks" <|
"Hello!".contains "[a-z]" Regex_Matcher_Data . should_be_true
"foobar" . contains "b.." Regex_Matcher_Data . should_be_true
"foob" . contains "b.." Regex_Matcher_Data . should_be_false
"Hello!".contains "[a-z]" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_true
"foobar" . contains "b.." (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_true
"foob" . contains "b.." (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_false
"123 meters and 4 centimeters" . contains "[0-9]+" Regex_Matcher_Data . should_be_true
"foo" . contains "[0-9]+" Regex_Matcher_Data . should_be_false
"123 meters and 4 centimeters" . contains "[0-9]+" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_true
"foo" . contains "[0-9]+" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_false
'ś' . contains 's' . should_be_false
's\u{301}' . contains 's' . should_be_false
@ -782,28 +782,28 @@ spec =
documenting here what is the current behaviour.
## This shows what regex is doing by default and we cannot easily fix
that.
's\u{301}' . contains 's' Regex_Matcher_Data . should_be_true
'ś' . contains 's' Regex_Matcher_Data . should_be_false
's\u{301}' . contains 'ś' Regex_Matcher_Data . should_be_true
'ś' . contains 's\u{301}' Regex_Matcher_Data . should_be_true
's\u{301}' . contains 's' (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_true
'ś' . contains 's' (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_false
's\u{301}' . contains 'ś' (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_true
'ś' . contains 's\u{301}' (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_true
"Cześć" . contains "ś" Regex_Matcher_Data . should_be_true
"Cześć" . contains 's\u{301}' Regex_Matcher_Data . should_be_true
'Czes\u{301}c\u{301}' . contains 's\u{301}' Regex_Matcher_Data . should_be_true
'Czes\u{301}c\u{301}' . contains 'ś' Regex_Matcher_Data . should_be_true
"Cześć" . contains "ś" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_true
"Cześć" . contains 's\u{301}' (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_true
'Czes\u{301}c\u{301}' . contains 's\u{301}' (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_true
'Czes\u{301}c\u{301}' . contains 'ś' (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_true
## These two tests below are disabled due to how regex is handling
letters with accents. See the tests above for explanation.
#"Cześć" . contains "s" Regex_Matcher_Data . should_be_false
#'Czes\u{301}c\u{301}' . contains 's' Regex_Matcher_Data . should_be_false
#"Cześć" . contains "s" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_false
#'Czes\u{301}c\u{301}' . contains 's' (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_false
"fooBar" . contains "b.." (Regex_Matcher_Data case_sensitive=Case_Insensitive_Data) . should_be_true
"foar" . contains "b.." (Regex_Matcher_Data case_sensitive=Case_Insensitive_Data) . should_be_false
"fooBar" . contains "b.." (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Insensitive) . should_be_true
"foar" . contains "b.." (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Insensitive) . should_be_false
long_text = """
Hello from a long text. EOL
SOL Hmm...
long_text . contains "EOL.SOL" (Regex_Matcher_Data dot_matches_newline=True) . should_be_true
long_text . contains "EOL.SOL" (Regex_Matcher_Data dot_matches_newline=False) . should_be_false
long_text . contains "EOL.SOL" ((Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) dot_matches_newline=True) . should_be_true
long_text . contains "EOL.SOL" ((Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) dot_matches_newline=False) . should_be_false
Test.specify "should check for starts_with using Unicode normalization" <|
"Hello".starts_with "He" . should_be_true
@ -827,36 +827,36 @@ spec =
Test.specify "starts_with should work as shown in the examples" <|
"Hello!".starts_with "Hello" . should_be_true
"Hello!".starts_with "hello" . should_be_false
"Hello!".starts_with "hello" (Text_Matcher_Data Case_Insensitive_Data) . should_be_true
"Hello!".starts_with "[a-z]" Regex_Matcher_Data . should_be_false
"Hello!".starts_with "[A-Z]" Regex_Matcher_Data . should_be_true
"Hello!".starts_with "hello" Text_Matcher.Case_Insensitive . should_be_true
"Hello!".starts_with "[a-z]" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_false
"Hello!".starts_with "[A-Z]" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_true
Test.specify "should allow for case-insensitive starts_with checks" <|
"Hello".starts_with "he" (Text_Matcher_Data Case_Insensitive_Data) . should_be_true
"Hello".starts_with "he" Text_Matcher.Case_Insensitive . should_be_true
"Ściana".starts_with 's\u{301}' (Text_Matcher_Data Case_Insensitive_Data) . should_be_true
"Ściana".starts_with 's' (Text_Matcher_Data Case_Insensitive_Data) . should_be_false
'S\u{301}ciana'.starts_with 'ś' (Text_Matcher_Data Case_Insensitive_Data) . should_be_true
'S\u{301}ciana'.starts_with 's\u{301}' (Text_Matcher_Data Case_Insensitive_Data) . should_be_true
'S\u{301}ciana'.starts_with 's' (Text_Matcher_Data Case_Insensitive_Data) . should_be_false
"Ściana".starts_with 's\u{301}' Text_Matcher.Case_Insensitive . should_be_true
"Ściana".starts_with 's' Text_Matcher.Case_Insensitive . should_be_false
'S\u{301}ciana'.starts_with 'ś' Text_Matcher.Case_Insensitive . should_be_true
'S\u{301}ciana'.starts_with 's\u{301}' Text_Matcher.Case_Insensitive . should_be_true
'S\u{301}ciana'.starts_with 's' Text_Matcher.Case_Insensitive . should_be_false
"ABC" . starts_with "A" (Text_Matcher_Data Case_Insensitive_Data) . should_be_true
"ABC" . starts_with "a" (Text_Matcher_Data Case_Insensitive_Data) . should_be_true
"ABC" . starts_with "C" (Text_Matcher_Data Case_Insensitive_Data) . should_be_false
"" . starts_with "foo" (Text_Matcher_Data Case_Insensitive_Data) . should_be_false
"abc" . starts_with "" (Text_Matcher_Data Case_Insensitive_Data) . should_be_true
"" . starts_with "" (Text_Matcher_Data Case_Insensitive_Data) . should_be_true
"fOo FOO foo" . starts_with "FoO" (Text_Matcher_Data Case_Insensitive_Data) . should_be_true
"ABC" . starts_with "A" Text_Matcher.Case_Insensitive . should_be_true
"ABC" . starts_with "a" Text_Matcher.Case_Insensitive . should_be_true
"ABC" . starts_with "C" Text_Matcher.Case_Insensitive . should_be_false
"" . starts_with "foo" Text_Matcher.Case_Insensitive . should_be_false
"abc" . starts_with "" Text_Matcher.Case_Insensitive . should_be_true
"" . starts_with "" Text_Matcher.Case_Insensitive . should_be_true
"fOo FOO foo" . starts_with "FoO" Text_Matcher.Case_Insensitive . should_be_true
"Hello!".starts_with "he" (Text_Matcher_Data Case_Insensitive_Data) . should_be_true
"Hello!".starts_with "he" Text_Matcher.Case_Insensitive . should_be_true
Test.specify "should allow for Regex starts_with checks" <|
"Hello!".starts_with "[A-Z]" Regex_Matcher_Data . should_be_true
"foobar" . starts_with ".o." Regex_Matcher_Data . should_be_true
"foob" . starts_with ".f." Regex_Matcher_Data . should_be_false
"Hello!".starts_with "[A-Z]" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_true
"foobar" . starts_with ".o." (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_true
"foob" . starts_with ".f." (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_false
"123 meters and 4 centimeters" . starts_with "[0-9]+" Regex_Matcher_Data . should_be_true
"foo 123" . starts_with "[0-9]+" Regex_Matcher_Data . should_be_false
"123 meters and 4 centimeters" . starts_with "[0-9]+" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_true
"foo 123" . starts_with "[0-9]+" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_false
# Correct non-regex behaviour for reference.
'ś' . starts_with 's' == False
@ -865,44 +865,44 @@ spec =
'ś' . starts_with 's\u{301}' == True
# These two behave as expected.
's\u{301}' . starts_with 'ś' Regex_Matcher_Data == True
'ś' . starts_with 's\u{301}' Regex_Matcher_Data == True
's\u{301}' . starts_with 'ś' (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) == True
'ś' . starts_with 's\u{301}' (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) == True
## These two are included to document the current behaviour
(even though ideally, we would want them to return False).
'ś' . starts_with 's' Regex_Matcher_Data == True
's\u{301}' . starts_with 's' Regex_Matcher_Data == True
'ś' . starts_with 's' (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) == True
's\u{301}' . starts_with 's' (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) == True
"ściana" . starts_with "ś" Regex_Matcher_Data . should_be_true
"ściana" . starts_with 's\u{301}' Regex_Matcher_Data . should_be_true
's\u{301}ciana' . starts_with 's\u{301}' Regex_Matcher_Data . should_be_true
's\u{301}ciana' . starts_with 'ś' Regex_Matcher_Data . should_be_true
"ściana" . starts_with "ś" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_true
"ściana" . starts_with 's\u{301}' (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_true
's\u{301}ciana' . starts_with 's\u{301}' (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_true
's\u{301}ciana' . starts_with 'ś' (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_true
## These two tests below are disabled due to how regex is handling
letters with accents. See the tests above for explanation.
#"ściana" . starts_with "s" Regex_Matcher_Data . should_be_false
# 's\u{301}ciana' . starts_with 's' Regex_Matcher_Data . should_be_false
#"ściana" . starts_with "s" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_false
# 's\u{301}ciana' . starts_with 's' (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_false
"fOOBar" . starts_with ".o." (Regex_Matcher_Data case_sensitive=Case_Insensitive_Data) . should_be_true
"faaaar" . starts_with ".o." (Regex_Matcher_Data case_sensitive=Case_Insensitive_Data) . should_be_false
"fOOBar" . starts_with ".o." (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Insensitive) . should_be_true
"faaaar" . starts_with ".o." (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Insensitive) . should_be_false
long_text = """
EOL
SOL Hmm...
long_text . starts_with "EOL.SOL" (Regex_Matcher_Data dot_matches_newline=True) . should_be_true
long_text . starts_with "EOL.SOL" (Regex_Matcher_Data dot_matches_newline=False) . should_be_false
long_text . starts_with "EOL.SOL" ((Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) dot_matches_newline=True) . should_be_true
long_text . starts_with "EOL.SOL" ((Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) dot_matches_newline=False) . should_be_false
"aaazzz" . starts_with "a|b" Regex_Matcher_Data . should_be_true
"bbbzzz" . starts_with "a|b" Regex_Matcher_Data . should_be_true
"zzzaaa" . starts_with "a|b" Regex_Matcher_Data . should_be_false
"zzzbbb" . starts_with "a|b" Regex_Matcher_Data . should_be_false
"aaazzz" . starts_with "(a|b){2}" Regex_Matcher_Data . should_be_true
"bbbzzz" . starts_with "(a|b){2}" Regex_Matcher_Data . should_be_true
"zzzaaa" . starts_with "(a|b){2}" Regex_Matcher_Data . should_be_false
"ABC" . starts_with "\AA" Regex_Matcher_Data . should_be_true
"ABC" . starts_with "\AA\z" Regex_Matcher_Data . should_be_false
"foobar" . starts_with "" Regex_Matcher_Data . should_be_true
"" . starts_with "" Regex_Matcher_Data . should_be_true
"aaazzz" . starts_with "a|b" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_true
"bbbzzz" . starts_with "a|b" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_true
"zzzaaa" . starts_with "a|b" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_false
"zzzbbb" . starts_with "a|b" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_false
"aaazzz" . starts_with "(a|b){2}" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_true
"bbbzzz" . starts_with "(a|b){2}" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_true
"zzzaaa" . starts_with "(a|b){2}" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_false
"ABC" . starts_with "\AA" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_true
"ABC" . starts_with "\AA\z" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_false
"foobar" . starts_with "" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_true
"" . starts_with "" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_true
Test.specify "should check for ends_with using Unicode normalization" <|
"Hello".ends_with "lo" . should_be_true
@ -925,64 +925,64 @@ spec =
Test.specify "ends_with should work as shown in the examples" <|
"Hello World".ends_with "World" . should_be_true
"Hello World".ends_with "world" . should_be_false
"Hello World".ends_with "world" (Text_Matcher_Data Case_Insensitive_Data) . should_be_true
"Hello World".ends_with "[A-Z][a-z]{4}" Regex_Matcher_Data . should_be_true
"Hello World".ends_with "world" Text_Matcher.Case_Insensitive . should_be_true
"Hello World".ends_with "[A-Z][a-z]{4}" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_true
Test.specify "should allow for case-insensitive ends_with checks" <|
"Hello".ends_with "LO" (Text_Matcher_Data Case_Insensitive_Data) . should_be_true
"Hello".ends_with "LO" Text_Matcher.Case_Insensitive . should_be_true
"rzeczywistość".ends_with 'C\u{301}' (Text_Matcher_Data Case_Insensitive_Data) . should_be_true
"rzeczywistość".ends_with 'C' (Text_Matcher_Data Case_Insensitive_Data) . should_be_false
'rzeczywistos\u{301}c\u{301}'.ends_with 'Ć' (Text_Matcher_Data Case_Insensitive_Data) . should_be_true
'rzeczywistos\u{301}c\u{301}'.ends_with 'C\u{301}' (Text_Matcher_Data Case_Insensitive_Data) . should_be_true
'rzeczywistos\u{301}c\u{301}'.ends_with 'C' (Text_Matcher_Data Case_Insensitive_Data) . should_be_false
"rzeczywistość".ends_with 'C\u{301}' Text_Matcher.Case_Insensitive . should_be_true
"rzeczywistość".ends_with 'C' Text_Matcher.Case_Insensitive . should_be_false
'rzeczywistos\u{301}c\u{301}'.ends_with 'Ć' Text_Matcher.Case_Insensitive . should_be_true
'rzeczywistos\u{301}c\u{301}'.ends_with 'C\u{301}' Text_Matcher.Case_Insensitive . should_be_true
'rzeczywistos\u{301}c\u{301}'.ends_with 'C' Text_Matcher.Case_Insensitive . should_be_false
"ABC" . ends_with "C" (Text_Matcher_Data Case_Insensitive_Data) . should_be_true
"ABC" . ends_with "c" (Text_Matcher_Data Case_Insensitive_Data) . should_be_true
"ABC" . ends_with "A" (Text_Matcher_Data Case_Insensitive_Data) . should_be_false
"" . ends_with "foo" (Text_Matcher_Data Case_Insensitive_Data) . should_be_false
"abc" . ends_with "" (Text_Matcher_Data Case_Insensitive_Data) . should_be_true
"" . ends_with "" (Text_Matcher_Data Case_Insensitive_Data) . should_be_true
"fOo FOO fOo" . ends_with "FoO" (Text_Matcher_Data Case_Insensitive_Data) . should_be_true
"ABC" . ends_with "C" Text_Matcher.Case_Insensitive . should_be_true
"ABC" . ends_with "c" Text_Matcher.Case_Insensitive . should_be_true
"ABC" . ends_with "A" Text_Matcher.Case_Insensitive . should_be_false
"" . ends_with "foo" Text_Matcher.Case_Insensitive . should_be_false
"abc" . ends_with "" Text_Matcher.Case_Insensitive . should_be_true
"" . ends_with "" Text_Matcher.Case_Insensitive . should_be_true
"fOo FOO fOo" . ends_with "FoO" Text_Matcher.Case_Insensitive . should_be_true
Test.specify "should allow for Regex ends_with checks" <|
"Hello".ends_with "[a-z]" Regex_Matcher_Data . should_be_true
"Hello!".ends_with "[a-z]" Regex_Matcher_Data . should_be_false
"Hello".ends_with "[a-z]" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive) . should_be_true
"Hello!".ends_with "[a-z]" Regex_Matcher.Regex_Matcher_Data . should_be_false
"foobar" . ends_with ".o." Regex_Matcher_Data . should_be_false
"foobar" . ends_with ".a." Regex_Matcher_Data . should_be_true
"foobar" . ends_with ".o." Regex_Matcher.Regex_Matcher_Data . should_be_false
"foobar" . ends_with ".a." Regex_Matcher.Regex_Matcher_Data . should_be_true
"123 meters and 4 centimeters" . ends_with "[0-9]+" Regex_Matcher_Data . should_be_false
"foo 123" . ends_with "[0-9]+" Regex_Matcher_Data . should_be_true
"123 meters and 4 centimeters" . ends_with "[0-9]+" Regex_Matcher.Regex_Matcher_Data . should_be_false
"foo 123" . ends_with "[0-9]+" Regex_Matcher.Regex_Matcher_Data . should_be_true
"rzeczywistość" . ends_with "ć" Regex_Matcher_Data . should_be_true
"rzeczywistość" . ends_with 'c\u{301}' Regex_Matcher_Data . should_be_true
'rzeczywistos\u{301}c\u{301}' . ends_with 'c\u{301}' Regex_Matcher_Data . should_be_true
'rzeczywistos\u{301}c\u{301}' . ends_with 'ć' Regex_Matcher_Data . should_be_true
"rzeczywistość" . ends_with "c" Regex_Matcher_Data . should_be_false
'rzeczywistos\u{301}c\u{301}' . ends_with 'c' Regex_Matcher_Data . should_be_false
"rzeczywistość" . ends_with "ć" Regex_Matcher.Regex_Matcher_Data . should_be_true
"rzeczywistość" . ends_with 'c\u{301}' Regex_Matcher.Regex_Matcher_Data . should_be_true
'rzeczywistos\u{301}c\u{301}' . ends_with 'c\u{301}' Regex_Matcher.Regex_Matcher_Data . should_be_true
'rzeczywistos\u{301}c\u{301}' . ends_with 'ć' Regex_Matcher.Regex_Matcher_Data . should_be_true
"rzeczywistość" . ends_with "c" Regex_Matcher.Regex_Matcher_Data . should_be_false
'rzeczywistos\u{301}c\u{301}' . ends_with 'c' Regex_Matcher.Regex_Matcher_Data . should_be_false
'rzeczywistos\u{301}c\u{301}' . ends_with 'Ć' (Regex_Matcher_Data case_sensitive=Case_Insensitive_Data) . should_be_true
"fOOBar" . ends_with ".A." (Regex_Matcher_Data case_sensitive=Case_Insensitive_Data) . should_be_true
"faaaar" . ends_with ".o." (Regex_Matcher_Data case_sensitive=Case_Insensitive_Data) . should_be_false
'rzeczywistos\u{301}c\u{301}' . ends_with 'Ć' (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Insensitive) . should_be_true
"fOOBar" . ends_with ".A." (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Insensitive) . should_be_true
"faaaar" . ends_with ".o." (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Insensitive) . should_be_false
long_text = """
Hnnnn EOL
SOL
long_text . ends_with "EOL.SOL" (Regex_Matcher_Data dot_matches_newline=True) . should_be_true
long_text . ends_with "EOL.SOL" (Regex_Matcher_Data dot_matches_newline=False) . should_be_false
long_text . ends_with "EOL.SOL" (Regex_Matcher.Regex_Matcher_Data dot_matches_newline=True) . should_be_true
long_text . ends_with "EOL.SOL" (Regex_Matcher.Regex_Matcher_Data dot_matches_newline=False) . should_be_false
"zzzaaa" . ends_with "a|b" Regex_Matcher_Data . should_be_true
"zzzbbb" . ends_with "a|b" Regex_Matcher_Data . should_be_true
"aaazzz" . ends_with "a|b" Regex_Matcher_Data . should_be_false
"bbbzzz" . ends_with "a|b" Regex_Matcher_Data . should_be_false
"zzzaaa" . ends_with "(a|b){2}" Regex_Matcher_Data . should_be_true
"zzzbbb" . ends_with "(a|b){2}" Regex_Matcher_Data . should_be_true
"aaazzz" . ends_with "(a|b){2}" Regex_Matcher_Data . should_be_false
"ABC" . ends_with "C\z" Regex_Matcher_Data . should_be_true
"ABC" . ends_with "\AC\z" Regex_Matcher_Data . should_be_false
"foobar" . ends_with "" Regex_Matcher_Data . should_be_true
"" . ends_with "" Regex_Matcher_Data . should_be_true
"zzzaaa" . ends_with "a|b" Regex_Matcher.Regex_Matcher_Data . should_be_true
"zzzbbb" . ends_with "a|b" Regex_Matcher.Regex_Matcher_Data . should_be_true
"aaazzz" . ends_with "a|b" Regex_Matcher.Regex_Matcher_Data . should_be_false
"bbbzzz" . ends_with "a|b" Regex_Matcher.Regex_Matcher_Data . should_be_false
"zzzaaa" . ends_with "(a|b){2}" Regex_Matcher.Regex_Matcher_Data . should_be_true
"zzzbbb" . ends_with "(a|b){2}" Regex_Matcher.Regex_Matcher_Data . should_be_true
"aaazzz" . ends_with "(a|b){2}" Regex_Matcher.Regex_Matcher_Data . should_be_false
"ABC" . ends_with "C\z" Regex_Matcher.Regex_Matcher_Data . should_be_true
"ABC" . ends_with "\AC\z" Regex_Matcher.Regex_Matcher_Data . should_be_false
"foobar" . ends_with "" Regex_Matcher.Regex_Matcher_Data . should_be_true
"" . ends_with "" Regex_Matcher.Regex_Matcher_Data . should_be_true
Test.specify "should allow to pad a text" <|
"Hello World!".pad 15 . should_equal "Hello World! "
@ -1091,7 +1091,7 @@ spec =
example_2 =
term = "straße"
text = "MONUMENTENSTRASSE 42"
match = text . location_of term matcher=(Text_Matcher_Data Case_Insensitive_Data)
match = text . location_of term matcher=Text_Matcher.Case_Insensitive
term.length . should_equal 6
match.length . should_equal 7
@ -1099,11 +1099,11 @@ spec =
ligatures = "ffiffl"
ligatures.length . should_equal 2
term_1 = "IFF"
match_1 = ligatures . location_of term_1 matcher=(Text_Matcher_Data Case_Insensitive_Data)
match_1 = ligatures . location_of term_1 matcher=Text_Matcher.Case_Insensitive
term_1.length . should_equal 3
match_1.length . should_equal 2
term_2 = "ffiffl"
match_2 = ligatures . location_of term_2 matcher=(Text_Matcher_Data Case_Insensitive_Data)
match_2 = ligatures . location_of term_2 matcher=Text_Matcher.Case_Insensitive
term_2.length . should_equal 6
match_2.length . should_equal 2
match_1 . should_equal match_2
@ -1115,16 +1115,16 @@ spec =
example_5 =
term = "strasse"
text = "MONUMENTENSTRASSE ist eine große Straße."
match = text . location_of_all term matcher=(Text_Matcher_Data Case_Insensitive_Data)
match = text . location_of_all term matcher=Text_Matcher.Case_Insensitive
term.length . should_equal 7
match . map .length . should_equal [7, 6]
example_6 =
ligatures = "ffifflFFIFF"
ligatures.length . should_equal 7
match_1 = ligatures . location_of_all "IFF" matcher=(Text_Matcher_Data Case_Insensitive_Data)
match_1 = ligatures . location_of_all "IFF" matcher=Text_Matcher.Case_Insensitive
match_1 . map .length . should_equal [2, 3]
match_2 = ligatures . location_of_all "ffiff" matcher=(Text_Matcher_Data Case_Insensitive_Data)
match_2 = ligatures . location_of_all "ffiff" matcher=Text_Matcher.Case_Insensitive
match_2 . map .length . should_equal [2, 5]
# Put them in blocks to avoid name clashes.
@ -1155,7 +1155,7 @@ spec =
Test.specify "should allow case-insensitive matching in location_of" <|
hello = "Hello WORLD!"
case_insensitive = Text_Matcher_Data Case_Insensitive_Data
case_insensitive = Text_Matcher.Case_Insensitive
hello.location_of "world" . should_equal Nothing
hello.location_of "world" matcher=case_insensitive . should_equal (Span_Data (Range_Data 6 11) hello)
@ -1206,8 +1206,8 @@ spec =
Test.specify "should allow regexes in location_of" <|
hello = "Hello World!"
regex = Regex_Matcher_Data
regex_insensitive = Regex_Matcher_Data case_sensitive=Case_Insensitive_Data
regex = Regex_Matcher.Regex_Matcher_Data
regex_insensitive = Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Insensitive
hello.location_of ".o" Matching_Mode.First matcher=regex . should_equal (Span_Data (Range_Data 3 5) hello)
hello.location_of ".o" Matching_Mode.Last matcher=regex . should_equal (Span_Data (Range_Data 6 8) hello)
hello.location_of_all ".o" matcher=regex . map .start . should_equal [3, 6]
@ -1221,7 +1221,7 @@ spec =
accents = 'a\u{301}e\u{301}o\u{301}'
accents.location_of accent_1 Regex_Mode.First matcher=regex . should_equal (Span_Data (Range_Data 1 2) accents)
Test.specify "should correctly handle regex edge cases in location_of" pending="Figure out how to make Regex correctly handle empty patterns." <|
regex = Regex_Matcher_Data
regex = Regex_Matcher.Regex_Matcher_Data
"".location_of "foo" matcher=regex . should_equal Nothing
"".location_of "foo" matcher=regex mode=Matching_Mode.Last . should_equal Nothing
"".location_of_all "foo" matcher=regex . should_equal []
@ -1234,11 +1234,11 @@ spec =
abc.location_of "" matcher=regex mode=Matching_Mode.Last . should_equal (Span_Data (Range_Data 3 3) abc)
Test.specify "should handle overlapping matches as shown in the examples"
"aaa".location_of "aa" mode=Matching_Mode.Last matcher=Text_Matcher_Data . should_equal (Span_Data (Range_Data 1 3) "aaa")
"aaa".location_of "aa" mode=Matching_Mode.Last matcher=Regex_Matcher_Data . should_equal (Span_Data (Range_Data 0 2) "aaa")
"aaa".location_of "aa" mode=Matching_Mode.Last matcher=Text_Matcher.Case_Sensitive . should_equal (Span_Data (Range_Data 1 3) "aaa")
"aaa".location_of "aa" mode=Matching_Mode.Last matcher=Regex_Matcher.Regex_Matcher_Data . should_equal (Span_Data (Range_Data 0 2) "aaa")
"aaa aaa".location_of "aa" mode=Matching_Mode.Last matcher=Text_Matcher_Data . should_equal (Span_Data (Range_Data 5 7) "aaa aaa")
"aaa aaa".location_of "aa" mode=Matching_Mode.Last matcher=Regex_Matcher_Data . should_equal (Span_Data (Range_Data 4 6) "aaa aaa")
"aaa aaa".location_of "aa" mode=Matching_Mode.Last matcher=Text_Matcher.Case_Sensitive . should_equal (Span_Data (Range_Data 5 7) "aaa aaa")
"aaa aaa".location_of "aa" mode=Matching_Mode.Last matcher=Regex_Matcher.Regex_Matcher_Data . should_equal (Span_Data (Range_Data 4 6) "aaa aaa")
Test.group "Regex matching" <|
Test.specify "should be possible on text" <|
@ -1350,34 +1350,34 @@ spec =
Test.group "Regex splitting" <|
Test.specify "should be possible on text" <|
splits = "abcde".split "[bd]" Regex_Matcher_Data
splits = "abcde".split "[bd]" Regex_Matcher.Regex_Matcher_Data
splits.length . should_equal 3
splits.at 0 . should_equal "a"
splits.at 1 . should_equal "c"
splits.at 2 . should_equal "e"
Test.specify "should be possible on unicode text" <|
match = "Korean: 건반 (hangul)".split " " Regex_Matcher_Data
match = "Korean: 건반 (hangul)".split " " Regex_Matcher.Regex_Matcher_Data
match.length . should_equal 3
match.at 0 . should_equal "Korean:"
match.at 1 . should_equal "건반"
match.at 2 . should_equal "(hangul)"
Test.specify "should be possible in ascii mode" <|
splits = "İiİ".split "\w" (Regex_Matcher_Data match_ascii=True)
splits = "İiİ".split "\w" (Regex_Matcher.Regex_Matcher_Data match_ascii=True)
splits.length . should_equal 2
splits.at 0 . should_equal "İ"
splits.at 1 . should_equal "İ"
Test.specify "should be possible in case-insensitive mode" <|
splits = "abaBa".split "b" (Regex_Matcher_Data case_sensitive=Case_Insensitive_Data)
splits = "abaBa".split "b" (Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Insensitive)
splits.length . should_equal 3
splits.at 0 . should_equal "a"
splits.at 1 . should_equal "a"
splits.at 2 . should_equal "a"
Test.specify "should be possible in dot_matches_newline mode" <|
splits = 'ab\nabcd'.split "b." (Regex_Matcher_Data dot_matches_newline=True)
splits = 'ab\nabcd'.split "b." (Regex_Matcher.Regex_Matcher_Data dot_matches_newline=True)
splits.length . should_equal 3
splits.at 0 . should_equal "a"
splits.at 1 . should_equal "a"
@ -1387,11 +1387,11 @@ spec =
text = """
Foo
bar
match = text.split "$" (Regex_Matcher_Data multiline=True)
match = text.split "$" (Regex_Matcher.Regex_Matcher_Data multiline=True)
match.length . should_equal 3
Test.specify "should be possible in comments mode" <|
splits = "abcde".split "[bd] # Split on the letters `b` and `d`" (Regex_Matcher_Data comments=True)
splits = "abcde".split "[bd] # Split on the letters `b` and `d`" (Regex_Matcher.Regex_Matcher_Data comments=True)
splits.length . should_equal 3
splits.at 0 . should_equal "a"
splits.at 1 . should_equal "c"
@ -1400,11 +1400,11 @@ spec =
Test.group "Text.replace" <|
Test.specify "should work as in examples" <|
'aaa'.replace 'aa' 'b' . should_equal 'ba'
"Hello World!".replace "[lo]" "#" matcher=Regex_Matcher_Data . should_equal "He### W#r#d!"
"Hello World!".replace "[lo]" "#" matcher=Regex_Matcher.Regex_Matcher_Data . should_equal "He### W#r#d!"
"Hello World!".replace "l" "#" mode=Matching_Mode.First . should_equal "He#lo World!"
'"abc" foo "bar" baz'.replace '"(.*?)"' '($1)' matcher=Regex_Matcher_Data . should_equal '(abc) foo (bar) baz'
'ß'.replace 'S' 'A' matcher=(Text_Matcher_Data Case_Insensitive_Data) . should_equal 'AA'
'affib'.replace 'i' 'X' matcher=(Text_Matcher_Data Case_Insensitive_Data) . should_equal 'aXb'
'"abc" foo "bar" baz'.replace '"(.*?)"' '($1)' matcher=Regex_Matcher.Regex_Matcher_Data . should_equal '(abc) foo (bar) baz'
'ß'.replace 'S' 'A' matcher=Text_Matcher.Case_Insensitive . should_equal 'AA'
'affib'.replace 'i' 'X' matcher=Text_Matcher.Case_Insensitive . should_equal 'aXb'
Test.specify "should correctly handle empty-string edge cases" <|
[Regex_Mode.All, Matching_Mode.First, Matching_Mode.Last] . each mode->
@ -1424,22 +1424,22 @@ spec =
"aaa aaa".replace "aa" "c" mode=Matching_Mode.Last . should_equal "aaa ac"
Test.specify "should correctly handle case-insensitive matches" <|
'AaąĄ' . replace "A" "-" matcher=(Text_Matcher_Data Case_Insensitive_Data) . should_equal '--ąĄ'
'AaąĄ' . replace "A" "-" matcher=Text_Matcher.Case_Insensitive . should_equal '--ąĄ'
'AaąĄ' . replace "A" "-" . should_equal '-aąĄ'
'HeLlO wOrLd' . replace 'hElLo' 'Hey,' matcher=(Text_Matcher_Data True) . should_equal 'HeLlO wOrLd'
'HeLlO wOrLd' . replace 'hElLo' 'Hey,' matcher=(Text_Matcher_Data Case_Insensitive_Data) . should_equal 'Hey, wOrLd'
'HeLlO wOrLd' . replace 'hElLo' 'Hey,' matcher=Text_Matcher.Case_Sensitive . should_equal 'HeLlO wOrLd'
'HeLlO wOrLd' . replace 'hElLo' 'Hey,' matcher=Text_Matcher.Case_Insensitive . should_equal 'Hey, wOrLd'
"Iiİı" . replace "i" "-" . should_equal "I-İı"
"Iiİı" . replace "I" "-" . should_equal "-iİı"
"Iiİı" . replace "İ" "-" . should_equal "Ii-ı"
"Iiİı" . replace "ı" "-" . should_equal "Iiİ-"
"Iiİı" . replace "i" "-" matcher=(Text_Matcher_Data Case_Insensitive_Data) . should_equal "--İı"
"Iiİı" . replace "I" "-" matcher=(Text_Matcher_Data Case_Insensitive_Data) . should_equal "--İı"
"Iiİı" . replace "İ" "-" matcher=(Text_Matcher_Data Case_Insensitive_Data) . should_equal "Ii-ı"
"Iiİı" . replace "ı" "-" matcher=(Text_Matcher_Data Case_Insensitive_Data) . should_equal "Iiİ-"
"Iiİı" . replace "i" "-" matcher=Text_Matcher.Case_Insensitive . should_equal "--İı"
"Iiİı" . replace "I" "-" matcher=Text_Matcher.Case_Insensitive . should_equal "--İı"
"Iiİı" . replace "İ" "-" matcher=Text_Matcher.Case_Insensitive . should_equal "Ii-ı"
"Iiİı" . replace "ı" "-" matcher=Text_Matcher.Case_Insensitive . should_equal "Iiİ-"
tr_insensitive = Text_Matcher_Data (Case_Insensitive_Data (Locale.new "tr"))
tr_insensitive = Text_Matcher.Case_Insensitive (Locale.new "tr")
"Iiİı" . replace "i" "-" matcher=tr_insensitive . should_equal "I--ı"
"Iiİı" . replace "I" "-" matcher=tr_insensitive . should_equal "-iİ-"
"Iiİı" . replace "İ" "-" matcher=tr_insensitive . should_equal "I--ı"
@ -1460,12 +1460,12 @@ spec =
'SŚS\u{301}' . replace 'ś' 'O' . should_equal 'SŚS\u{301}'
'SŚS\u{301}' . replace 's\u{301}' 'O' . should_equal 'SŚS\u{301}'
'SŚS\u{301}' . replace 's' 'O' matcher=(Text_Matcher_Data Case_Insensitive_Data) . should_equal 'OŚS\u{301}'
'SŚS\u{301}' . replace 's' 'O' Matching_Mode.Last matcher=(Text_Matcher_Data Case_Insensitive_Data) . should_equal 'OŚS\u{301}'
'ŚS\u{301}S' . replace 's' 'O' Matching_Mode.First matcher=(Text_Matcher_Data Case_Insensitive_Data) . should_equal 'ŚS\u{301}O'
'SŚS\u{301}' . replace 's' 'O' matcher=Text_Matcher.Case_Insensitive . should_equal 'OŚS\u{301}'
'SŚS\u{301}' . replace 's' 'O' Matching_Mode.Last matcher=Text_Matcher.Case_Insensitive . should_equal 'OŚS\u{301}'
'ŚS\u{301}S' . replace 's' 'O' Matching_Mode.First matcher=Text_Matcher.Case_Insensitive . should_equal 'ŚS\u{301}O'
'SŚS\u{301}' . replace 'ś' 'O' matcher=(Text_Matcher_Data Case_Insensitive_Data) . should_equal 'SOO'
'SŚS\u{301}' . replace 's\u{301}' 'O' matcher=(Text_Matcher_Data Case_Insensitive_Data) . should_equal 'SOO'
'SŚS\u{301}' . replace 'ś' 'O' matcher=Text_Matcher.Case_Insensitive . should_equal 'SOO'
'SŚS\u{301}' . replace 's\u{301}' 'O' matcher=Text_Matcher.Case_Insensitive . should_equal 'SOO'
'✨🚀🚧😍😃😍😎😙😉☺' . replace '🚧😍' '|-|:)' . should_equal '✨🚀|-|:)😃😍😎😙😉☺'
'Rocket Science' . replace 'Rocket' '🚀' . should_equal '🚀 Science'
@ -1477,64 +1477,64 @@ spec =
## Currently we lack 'resolution' to extract a partial match from
the ligature to keep it, probably would need some special
mapping.
'ffiffi'.replace 'ff' 'aa' matcher=(Text_Matcher_Data Case_Insensitive_Data) . should_equal 'aaaa'
'ffiffi'.replace 'ff' 'aa' mode=Matching_Mode.First matcher=(Text_Matcher_Data Case_Insensitive_Data) . should_equal 'aaffi'
'ffiffi'.replace 'ff' 'aa' mode=Matching_Mode.Last matcher=(Text_Matcher_Data Case_Insensitive_Data) . should_equal 'ffiaa'
'affiffib'.replace 'IF' 'X' matcher=(Text_Matcher_Data Case_Insensitive_Data) . should_equal 'aXb'
'aiffiffz' . replace 'if' '-' matcher=(Text_Matcher_Data Case_Insensitive_Data) . should_equal 'a--fz'
'AFFIB'.replace 'ffi' '-' matcher=(Text_Matcher_Data Case_Insensitive_Data) . should_equal 'A-B'
'ffiffi'.replace 'ff' 'aa' matcher=Text_Matcher.Case_Insensitive . should_equal 'aaaa'
'ffiffi'.replace 'ff' 'aa' mode=Matching_Mode.First matcher=Text_Matcher.Case_Insensitive . should_equal 'aaffi'
'ffiffi'.replace 'ff' 'aa' mode=Matching_Mode.Last matcher=Text_Matcher.Case_Insensitive . should_equal 'ffiaa'
'affiffib'.replace 'IF' 'X' matcher=Text_Matcher.Case_Insensitive . should_equal 'aXb'
'aiffiffz' . replace 'if' '-' matcher=Text_Matcher.Case_Insensitive . should_equal 'a--fz'
'AFFIB'.replace 'ffi' '-' matcher=Text_Matcher.Case_Insensitive . should_equal 'A-B'
'ß'.replace 'SS' 'A' matcher=(Text_Matcher_Data Case_Insensitive_Data) . should_equal 'A'
'ß'.replace 'S' 'A' matcher=(Text_Matcher_Data Case_Insensitive_Data) . should_equal 'AA'
'ß'.replace 'S' 'A' mode=Matching_Mode.First matcher=(Text_Matcher_Data Case_Insensitive_Data) . should_equal 'A'
'ß'.replace 'S' 'A' mode=Matching_Mode.Last matcher=(Text_Matcher_Data Case_Insensitive_Data) . should_equal 'A'
'STRASSE'.replace 'ß' '-' matcher=(Text_Matcher_Data Case_Insensitive_Data) . should_equal 'STRA-E'
'ß'.replace 'SS' 'A' matcher=Text_Matcher.Case_Insensitive . should_equal 'A'
'ß'.replace 'S' 'A' matcher=Text_Matcher.Case_Insensitive . should_equal 'AA'
'ß'.replace 'S' 'A' mode=Matching_Mode.First matcher=Text_Matcher.Case_Insensitive . should_equal 'A'
'ß'.replace 'S' 'A' mode=Matching_Mode.Last matcher=Text_Matcher.Case_Insensitive . should_equal 'A'
'STRASSE'.replace 'ß' '-' matcher=Text_Matcher.Case_Insensitive . should_equal 'STRA-E'
Test.specify "should perform simple replacement in Regex mode" <|
"ababab".replace "b" "a" matcher=Regex_Matcher_Data . should_equal "aaaaaa"
"ababab".replace "b" "a" mode=Matching_Mode.First matcher=Regex_Matcher_Data . should_equal "aaabab"
"ababab".replace "b" "a" mode=Matching_Mode.Last matcher=Regex_Matcher_Data . should_equal "ababaa"
"ababab".replace "b" "a" matcher=Regex_Matcher.Regex_Matcher_Data . should_equal "aaaaaa"
"ababab".replace "b" "a" mode=Matching_Mode.First matcher=Regex_Matcher.Regex_Matcher_Data . should_equal "aaabab"
"ababab".replace "b" "a" mode=Matching_Mode.Last matcher=Regex_Matcher.Regex_Matcher_Data . should_equal "ababaa"
"aaaa".replace "aa" "c" matcher=Regex_Matcher_Data . should_equal "cc"
"aaaa".replace "aa" "c" mode=Matching_Mode.First matcher=Regex_Matcher_Data . should_equal "caa"
"aaaa".replace "aa" "c" mode=Matching_Mode.Last matcher=Regex_Matcher_Data . should_equal "aac"
"aaaa".replace "aa" "c" matcher=Regex_Matcher.Regex_Matcher_Data . should_equal "cc"
"aaaa".replace "aa" "c" mode=Matching_Mode.First matcher=Regex_Matcher.Regex_Matcher_Data . should_equal "caa"
"aaaa".replace "aa" "c" mode=Matching_Mode.Last matcher=Regex_Matcher.Regex_Matcher_Data . should_equal "aac"
"aaa".replace "aa" "c" matcher=Regex_Matcher_Data . should_equal "ca"
"aaa".replace "aa" "c" mode=Matching_Mode.First matcher=Regex_Matcher_Data . should_equal "ca"
"aaa".replace "aa" "c" mode=Matching_Mode.Last matcher=Text_Matcher_Data . should_equal "ac"
"aaa".replace "aa" "c" mode=Matching_Mode.Last matcher=Regex_Matcher_Data . should_equal "ca"
"aaa".replace "aa" "c" matcher=Regex_Matcher.Regex_Matcher_Data . should_equal "ca"
"aaa".replace "aa" "c" mode=Matching_Mode.First matcher=Regex_Matcher.Regex_Matcher_Data . should_equal "ca"
"aaa".replace "aa" "c" mode=Matching_Mode.Last matcher=Text_Matcher.Case_Sensitive . should_equal "ac"
"aaa".replace "aa" "c" mode=Matching_Mode.Last matcher=Regex_Matcher.Regex_Matcher_Data . should_equal "ca"
"aaa aaa".replace "aa" "c" matcher=Text_Matcher_Data . should_equal "ca ca"
"aaa aaa".replace "aa" "c" mode=Matching_Mode.First matcher=Text_Matcher_Data . should_equal "ca aaa"
"aaa aaa".replace "aa" "c" mode=Matching_Mode.Last matcher=Text_Matcher_Data . should_equal "aaa ac"
"aaa aaa".replace "aa" "c" matcher=Regex_Matcher_Data . should_equal "ca ca"
"aaa aaa".replace "aa" "c" mode=Matching_Mode.First matcher=Regex_Matcher_Data . should_equal "ca aaa"
"aaa aaa".replace "aa" "c" mode=Matching_Mode.Last matcher=Regex_Matcher_Data . should_equal "aaa ca"
"aaa aaa".replace "aa" "c" matcher=Text_Matcher.Case_Sensitive . should_equal "ca ca"
"aaa aaa".replace "aa" "c" mode=Matching_Mode.First matcher=Text_Matcher.Case_Sensitive . should_equal "ca aaa"
"aaa aaa".replace "aa" "c" mode=Matching_Mode.Last matcher=Text_Matcher.Case_Sensitive . should_equal "aaa ac"
"aaa aaa".replace "aa" "c" matcher=Regex_Matcher.Regex_Matcher_Data . should_equal "ca ca"
"aaa aaa".replace "aa" "c" mode=Matching_Mode.First matcher=Regex_Matcher.Regex_Matcher_Data . should_equal "ca aaa"
"aaa aaa".replace "aa" "c" mode=Matching_Mode.Last matcher=Regex_Matcher.Regex_Matcher_Data . should_equal "aaa ca"
Test.specify "in Regex mode should work with Unicode" <|
"Korean: 건반".replace "건반" "keyboard" matcher=Regex_Matcher_Data . should_equal "Korean: keyboard"
'sśs\u{301}'.replace 'ś' '-' matcher=Regex_Matcher_Data . should_equal 's--'
'sśs\u{301}'.replace 's\u{301}' '-' matcher=Regex_Matcher_Data . should_equal 's--'
"Korean: 건반".replace "건반" "keyboard" matcher=Regex_Matcher.Regex_Matcher_Data . should_equal "Korean: keyboard"
'sśs\u{301}'.replace 'ś' '-' matcher=Regex_Matcher.Regex_Matcher_Data . should_equal 's--'
'sśs\u{301}'.replace 's\u{301}' '-' matcher=Regex_Matcher.Regex_Matcher_Data . should_equal 's--'
Test.specify "in Regex mode should support various Regex options" <|
r1 = "İiİ".replace "\w" "a" matcher=(Regex_Matcher_Data match_ascii=True)
r1 = "İiİ".replace "\w" "a" matcher=(Regex_Matcher.Regex_Matcher_Data match_ascii=True)
r1 . should_equal "İaİ"
r2 = "abaBa".replace "b" "a" matcher=(Regex_Matcher_Data case_sensitive=Case_Insensitive_Data)
r2 = "abaBa".replace "b" "a" matcher=(Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Insensitive)
r2 . should_equal "aaaaa"
r3 = 'ab\na'.replace "b." "a" matcher=(Regex_Matcher_Data dot_matches_newline=True)
r3 = 'ab\na'.replace "b." "a" matcher=(Regex_Matcher.Regex_Matcher_Data dot_matches_newline=True)
r3 . should_equal "aaa"
text = """
Foo
bar
r4 = text.replace '\n' "" matcher=(Regex_Matcher_Data multiline=True)
r4 = text.replace '\n' "" matcher=(Regex_Matcher.Regex_Matcher_Data multiline=True)
r4 . should_equal "Foobar"
r5 = "ababd".replace "b\w # Replacing a `b` followed by any word character" "a" matcher=(Regex_Matcher_Data comments=True)
r5 = "ababd".replace "b\w # Replacing a `b` followed by any word character" "a" matcher=(Regex_Matcher.Regex_Matcher_Data comments=True)
r5 . should_equal "aaa"
Test.specify "in Regex mode should allow referring to capture groups in substitutions" <|
'<a href="url">content</a>'.replace '<a href="(.*?)">(.*?)</a>' '$2 is at $1' matcher=Regex_Matcher_Data . should_equal 'content is at url'
'<a href="url">content</a>'.replace '<a href="(?<address>.*?)">(?<text>.*?)</a>' '${text} is at ${address}' matcher=Regex_Matcher_Data . should_equal 'content is at url'
'<a href="url">content</a>'.replace '<a href="(.*?)">(.*?)</a>' '$2 is at $1' matcher=Regex_Matcher.Regex_Matcher_Data . should_equal 'content is at url'
'<a href="url">content</a>'.replace '<a href="(?<address>.*?)">(?<text>.*?)</a>' '${text} is at ${address}' matcher=Regex_Matcher.Regex_Matcher_Data . should_equal 'content is at url'
main = Test.Suite.run_main spec