Widget Improvements (#10575)

- New centralised `make_any_selector` for creating dropdown for various types.
- Updated `Filter_Condition.default_widget` to be auto-scoped.
![image](https://github.com/user-attachments/assets/2786d512-6716-4d4b-b119-15054611c11c)
- Nested structure for Simple_Expressions.
![image](https://github.com/user-attachments/assets/09eda332-0888-41e7-8462-fc8566959da5)
This commit is contained in:
James Dunkerley 2024-07-17 20:53:17 +01:00 committed by GitHub
parent 39898da664
commit 771402acf6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 636 additions and 402 deletions

View File

@ -1,5 +1,6 @@
import project.Any.Any
import project.Data.Filter_Condition.Filter_Condition
import project.Data.Index_Sub_Range.Index_Sub_Range
import project.Data.List.List
import project.Data.Numbers.Integer
import project.Data.Ordering.Ordering
@ -22,7 +23,6 @@ import project.Meta
import project.Nothing.Nothing
import project.Panic.Panic
from project.Data.Boolean import Boolean, False, True
from project.Data.Index_Sub_Range import Index_Sub_Range
from project.Data.Range.Extensions import all
from project.Metadata import Display, Widget
@ -455,10 +455,11 @@ type Array
Selecting all elements that are greater than 3.
[1, 2, 3, 4, 5].to_array.filter (> 3)
[1, 2, 3, 4, 5].to_array.filter (Filter_Condition.Greater than=3)
[1, 2, 3, 4, 5].to_array.filter (..Greater than=3)
@filter Filter_Condition.default_widget
filter : (Filter_Condition | (Any -> Boolean)) -> Vector Any
filter self (filter : Filter_Condition | (Any -> Boolean)) = Array_Like_Helpers.filter self filter
filter self (filter : Filter_Condition | (Any -> Boolean)) =
Array_Like_Helpers.filter self filter
## GROUP Calculations
ICON union
@ -576,7 +577,7 @@ type Array
> Example
Splitting an array into elements that start with a prefix.
["a", "b", "ax", "bx"].to_array.partition (Filter_Condition.Starts_With "a") == (Pair ["a", "ax"].to_array ["b", "bx"].to_array)
["a", "b", "ax", "bx"].to_array.partition (..Starts_With "a") == (Pair ["a", "ax"].to_array ["b", "bx"].to_array)
> Example
Splitting an array into even and odd elements.
@ -821,7 +822,7 @@ type Array
> Example
Checking if any element of the array is larger than 3.
[1, 2, 3, 4, 5].to_array.any (Filter_Condition.Greater than=3)
[1, 2, 3, 4, 5].to_array.any (..Greater than=3)
> Example
Checking if any element of the array is even.
@ -829,7 +830,8 @@ type Array
[1, 2, 3, 4, 5].to_array.any (x-> x%2 == 0)
@condition Filter_Condition.default_widget
any : (Filter_Condition | (Any -> Boolean)) -> Boolean
any self (condition : Filter_Condition | (Any -> Boolean)) = Array_Like_Helpers.any self condition
any self (condition : Filter_Condition | (Any -> Boolean)) =
Array_Like_Helpers.any self condition
## GROUP Logical
ICON preparation
@ -842,7 +844,7 @@ type Array
> Example
Check if all elements in the array are less than zero.
[-1, 1, 5, 8].to_array.all (Filter_Condition.Less than=0)
[-1, 1, 5, 8].to_array.all (..Less than=0)
> Example
Check if all elements in the array are even.
@ -850,7 +852,8 @@ type Array
[-1, 1, 5, 8].to_array.all (x-> x%2 == 0)
@condition Filter_Condition.default_widget
all : (Filter_Condition | (Any -> Boolean)) -> Boolean
all self (condition : Filter_Condition | (Any -> Boolean)) = Array_Like_Helpers.all self condition
all self (condition : Filter_Condition | (Any -> Boolean)) =
Array_Like_Helpers.all self condition
## GROUP Logical
ICON preparation

View File

@ -19,6 +19,7 @@ from project.Data.Filter_Condition.Filter_Condition import all
from project.Data.Text.Extensions import all
from project.Metadata import Display, make_single_choice, Widget
from project.Metadata.Choice import Option
from project.Widget_Helpers import make_any_selector
polyglot java import org.enso.base.Regex_Utils
@ -237,53 +238,45 @@ type Filter_Condition
## PRIVATE
Creates a Single_Choice Widget for delimiters.
default_widget : Boolean -> Boolean -> Boolean -> Boolean -> Boolean -> Widget
default_widget include_comparable=True include_text=True include_boolean=True include_nullable=True include_numeric=True =
text = if include_text then [Option "<Text Value>" "''"] else []
number = if include_numeric then [Option "<Number Value>" "0"] else []
boolean = if include_boolean then [Option "<True/False>" "True"] else []
with_all_types = Widget.Single_Choice values=text+number+boolean display=Display.Always
with_number_text = Widget.Single_Choice values=text+number display=Display.Always
## Can't use auto-scoping as we allow predicates or a Filter_Condition.
fqn = Meta.get_qualified_type_name Filter_Condition
default_widget : Boolean -> Boolean -> Boolean -> Boolean -> Boolean -> Boolean -> Widget
default_widget include_comparable=True include_text=True include_boolean=True include_nullable=True include_numeric=True include_date=True include_time=True include_date_time=True =
options = Vector.build builder->
builder.append (Option "Equals" fqn+".Equal" [["to", with_all_types]])
builder.append (Option "Not Equals" fqn+".Not_Equal" [["to", with_all_types]])
equatable_types = make_any_selector add_text=include_text add_boolean=include_boolean add_number=include_numeric add_date=include_date add_time=include_time add_date_time=include_date_time
builder.append (Option "Equals" "..Equal" [["to", equatable_types]])
builder.append (Option "Not Equals" "..Not_Equal" [["to", equatable_types]])
if include_comparable then
builder.append (Option "Less Than" fqn+".Less" [["than", with_number_text]])
builder.append (Option "Less Than Or Equal" fqn+".Equal_Or_Less" [["than", with_number_text]])
builder.append (Option "Greater Than" fqn+".Greater" [["than", with_number_text]])
builder.append (Option "Greater Than Or Equal" fqn+".Equal_Or_Greater" [["than", with_number_text]])
builder.append (Option "Between" fqn+".Between" [["lower", with_number_text], ["upper", with_number_text]])
comparable_types = make_any_selector add_text=include_text add_number=include_numeric add_date=include_date add_time=include_time add_date_time=include_date_time
builder.append (Option "Less Than" "..Less" [["than", comparable_types]])
builder.append (Option "Less Than Or Equal" "..Equal_Or_Less" [["than", comparable_types]])
builder.append (Option "Greater Than" "..Greater" [["than", comparable_types]])
builder.append (Option "Greater Than Or Equal" "..Equal_Or_Greater" [["than", comparable_types]])
builder.append (Option "Between" "..Between" [["lower", comparable_types], ["upper", comparable_types]])
if include_numeric then
builder.append (Option "Is Finite" fqn+".Is_Finite")
builder.append (Option "Is Infinite" fqn+".Is_Infinite")
builder.append (Option "Is NaN" fqn+".Is_Nan")
builder.append (Option "Is Finite" "..Is_Finite")
builder.append (Option "Is Infinite" "..Is_Infinite")
builder.append (Option "Is NaN" "..Is_Nan")
if include_boolean then
builder.append (Option "Is True" fqn+".Is_True")
builder.append (Option "Is False" fqn+".Is_False")
builder.append (Option "Is True" "..Is_True")
builder.append (Option "Is False" "..Is_False")
if include_nullable then
builder.append (Option "Is Nothing" fqn+".Is_Nothing")
builder.append (Option "Is Not Nothing" fqn+".Not_Nothing")
builder.append (Option "Is Nothing" "..Is_Nothing")
builder.append (Option "Is Not Nothing" "..Not_Nothing")
if include_text then
builder.append (Option "Equals Ignore Case" fqn+".Equal_Ignore_Case" [["to", Widget.Text_Input]])
builder.append (Option "Starts With" fqn+".Starts_With" [["prefix", Widget.Text_Input]])
builder.append (Option "Ends With" fqn+".Ends_With" [["suffix", Widget.Text_Input]])
builder.append (Option "Contains" fqn+".Contains" [["substring", Widget.Text_Input]])
builder.append (Option "Is Empty" fqn+".Is_Empty")
builder.append (Option "Is Not Empty" fqn+".Not_Empty")
builder.append (Option "Like" fqn+".Like" [["pattern", Widget.Text_Input]])
builder.append (Option "Equals Ignore Case" "..Equal_Ignore_Case" [["to", Widget.Text_Input]])
builder.append (Option "Starts With" "..Starts_With" [["prefix", Widget.Text_Input]])
builder.append (Option "Ends With" "..Ends_With" [["suffix", Widget.Text_Input]])
builder.append (Option "Contains" "..Contains" [["substring", Widget.Text_Input]])
builder.append (Option "Is Empty" "..Is_Empty")
builder.append (Option "Is Not Empty" "..Not_Empty")
builder.append (Option "Like" "..Like" [["pattern", Widget.Text_Input]])
value_editor = Widget.Vector_Editor item_editor=with_all_types display=Display.Always item_default=''
builder.append (Option "Is In" fqn+".Is_In" [["values", value_editor]])
value_editor = Widget.Vector_Editor item_editor=equatable_types display=Display.Always item_default=''
builder.append (Option "Is In" "..Is_In" [["values", value_editor]])
make_single_choice options
@ -302,8 +295,8 @@ sql_like_to_regex (sql_pattern : Text) =
## PRIVATE
unify_condition_or_predicate : Filter_Condition | (Any -> Boolean) -> (Any -> Boolean)
unify_condition_or_predicate (condition_or_predicate : Filter_Condition | (Any -> Boolean)) =
case condition_or_predicate of
unify_condition_or_predicate (condition_or_predicate : Filter_Condition | Function) =
case Filter_Condition.resolve_auto_scoped condition_or_predicate of
condition : Filter_Condition -> condition.to_predicate
predicate -> predicate
@ -311,7 +304,11 @@ unify_condition_or_predicate (condition_or_predicate : Filter_Condition | (Any -
unify_condition_predicate_or_element condition =
case condition of
condition : Filter_Condition -> condition.to_predicate
predicate : Function -> predicate
predicate : Function ->
resolved = Filter_Condition.resolve_auto_scoped predicate
case resolved of
condition : Filter_Condition -> condition.to_predicate
_ -> resolved
element -> (== element)
## PRIVATE

View File

@ -171,7 +171,7 @@ type List
import Standard.Examples
example_any = Examples.list.any (Filter_Condition.Greater than=5)
example_any = Examples.list.any (..Greater than=5)
> Example
Check if any element of the list is even.
@ -203,7 +203,7 @@ type List
import Standard.Examples
example_all = Examples.list.all (Filter_Condition.Greater than=0)
example_all = Examples.list.all (..Greater than=0)
> Example
Check if all elements in the list are even.
@ -277,7 +277,7 @@ type List
import Standard.Examples
example_filter = Examples.list.filter (< 3)
example_filter = Examples.list.filter (Filter_Condition.Less than=3)
example_filter = Examples.list.filter (..Less than=3)
@filter Filter_Condition.default_widget
filter : (Filter_Condition | (Any -> Boolean)) -> List Any
filter self (filter : Filter_Condition | (Any -> Boolean)) =

View File

@ -197,7 +197,7 @@ type Range
Selecting all elements that are greater than 3.
(0.up_to 7).filter (> 3)
(0.up_to 7).filter (Filter_Condition.Greater than=3)
(0.up_to 7).filter (..Greater than=3)
@filter range_default_filter_condition_widget
filter : (Filter_Condition | (Integer -> Boolean)) -> Vector Integer
filter self (filter : Filter_Condition | (Integer -> Boolean)) =
@ -365,7 +365,7 @@ type Range
> Example
Checking that all numbers in the range are greater than 5.
10.up_to 100 . all (Filter_Condition.Greater than=5)
10.up_to 100 . all (..Greater than=5)
> Example
Checking that all numbers in the range are even.
@ -388,7 +388,7 @@ type Range
> Example
Checking that at least one number in the range is greater than 10.
1.up_to 100 . any (Filter_Condition.Greater than=10)
1.up_to 100 . any (..Greater than=10)
> Example
Checking that at least one number in the range is even.
@ -396,7 +396,8 @@ type Range
1.up_to 100 . any (x-> x%2 == 0)
@condition range_default_filter_condition_widget
any : (Filter_Condition | (Integer -> Boolean)) -> Boolean
any self (condition : Filter_Condition | (Integer -> Boolean)) = self.find condition . is_nothing . not
any self (condition : Filter_Condition | (Integer -> Boolean)) =
self.find condition . is_nothing . not
## GROUP Selections
ICON find
@ -418,7 +419,7 @@ type Range
> Example
Get the first number in the range that is greater than 10.
1.up_to 100 . find (Filter_Condition.Greater than=10)
1.up_to 100 . find (..Greater than=10)
@condition range_default_filter_condition_widget
find : (Filter_Condition | (Integer -> Boolean)) -> Integer -> Any -> Any
find self (condition : Filter_Condition | (Integer -> Boolean)) (start : Integer = 0) ~if_missing=Nothing =
@ -471,7 +472,8 @@ type Range
check_start_valid start self used_start->
case condition of
element : Integer -> get_index self used_start self.length-1 element
f : Function ->
_ : Function ->
f = unify_condition_or_predicate condition
result = find_internal self used_start f
if result.is_nothing then Nothing else result.second
fc : Filter_Condition ->
@ -500,7 +502,8 @@ type Range
check_start_valid start self include_end=False used_start->
case condition of
element : Integer -> get_index self 0 used_start element
f : Function ->
_ : Function ->
f = unify_condition_or_predicate condition
start_value = self.start + used_start*self.step
go current idx =
if f current then idx else
@ -606,7 +609,7 @@ get_index range min max value =
## PRIVATE
range_default_filter_condition_widget =
Filter_Condition.default_widget include_text=False include_boolean=False include_nullable=False
Filter_Condition.default_widget include_text=False include_boolean=False include_nullable=False include_date=False include_time=False include_date_time=False
## PRIVATE
Vector.from (that:Range) = that.to_vector

View File

@ -256,7 +256,7 @@ type Date_Range
Selecting all elements that are greater than 2020-10-12.
(Date.new 2020 10 01).up_to (Date.new 2020 10 15) . filter (> (Date.new 2020 10 12))
(Date.new 2020 10 01).up_to (Date.new 2020 10 15) . filter (Filter_Condition.Greater than=(Date.new 2020 10 12))
(Date.new 2020 10 01).up_to (Date.new 2020 10 15) . filter (..Greater than=(Date.new 2020 10 12))
@filter date_range_default_filter_condition_widget
filter : (Filter_Condition | (Date -> Boolean)) -> Vector Date
filter self (filter : Filter_Condition | (Date -> Boolean)) =
@ -401,10 +401,11 @@ type Date_Range
> Example
Checking that at least one date in the range is after 2020-10-01.
(Date.new 2020 10 01).up_to (Date.new 2020 10 31) . any (Filter_Condition.Greater (Date.new 2020 10 01))
(Date.new 2020 10 01).up_to (Date.new 2020 10 31) . any (..Greater (Date.new 2020 10 01))
@condition date_range_default_filter_condition_widget
any : (Filter_Condition | (Date -> Boolean)) -> Boolean
any self (condition : Filter_Condition | (Date -> Boolean)) = self.find condition . is_nothing . not
any self (condition : Filter_Condition | (Date -> Boolean)) =
self.find condition . is_nothing . not
## GROUP Selections
ICON find
@ -605,7 +606,7 @@ unify_condition_for_index_of (condition : Date | Filter_Condition | Function) =
## PRIVATE
date_range_default_filter_condition_widget =
Filter_Condition.default_widget include_text=False include_boolean=False include_numeric=False include_nullable=False
Filter_Condition.default_widget include_text=False include_boolean=False include_numeric=False include_nullable=False include_time=False include_date_time=False
## PRIVATE
Vector.from (that:Date_Range) = that.to_vector

View File

@ -1,6 +1,7 @@
import project.Any.Any
import project.Data.Array.Array
import project.Data.Filter_Condition.Filter_Condition
import project.Data.Index_Sub_Range.Index_Sub_Range
import project.Data.List.List
import project.Data.Numbers.Integer
import project.Data.Pair.Pair
@ -26,8 +27,6 @@ import project.Panic.Panic
import project.Random.Random
import project.Warning.Warning
from project.Data.Boolean import Boolean, False, True
from project.Data.Filter_Condition import unify_condition_or_predicate, unify_condition_predicate_or_element
from project.Data.Index_Sub_Range import Index_Sub_Range
from project.Data.Ordering import all
from project.Data.Range.Extensions import all
from project.Metadata import Display, Widget
@ -468,7 +467,7 @@ type Vector a
> Example
Checking if any element of the vector is larger than 3.
[1, 2, 3, 4, 5].any (Filter_Condition.Greater than=3)
[1, 2, 3, 4, 5].any (..Greater than=3)
> Example
Checking if any element of the vector is even.
@ -490,7 +489,7 @@ type Vector a
> Example
Check if all elements in the vector are less than zero.
[-1, 1, 5, 8].all (Filter_Condition.Less than=0)
[-1, 1, 5, 8].all (..Less than=0)
> Example
Check if all elements in the vector are even.
@ -551,7 +550,7 @@ type Vector a
Selecting all elements that are greater than 3.
[1, 2, 3, 4, 5].filter (> 3)
[1, 2, 3, 4, 5].filter (Filter_Condition.Greater than=3)
[1, 2, 3, 4, 5].filter (..Greater than=3)
@filter Filter_Condition.default_widget
filter : (Filter_Condition | (Any -> Boolean)) -> Vector Any
filter self (filter : Filter_Condition | (Any -> Boolean)) =
@ -593,7 +592,7 @@ type Vector a
> Example
Splitting a vector into elements that start with a prefix.
["a", "b", "ax", "bx"].partition (Filter_Condition.Starts_With "a") == (Pair ["a", "ax"] ["b", "bx"])
["a", "b", "ax", "bx"].partition (..Starts_With "a") == (Pair ["a", "ax"] ["b", "bx"])
> Example
Splitting a vector into even and odd elements.
@ -1508,8 +1507,7 @@ type Builder
@condition Filter_Condition.default_widget
any : (Filter_Condition | (Any -> Boolean)) -> Boolean
any self (condition : Filter_Condition | (Any -> Boolean)) =
predicate = unify_condition_or_predicate condition
0.up_to self.length . any (idx -> (predicate (self.java_builder.get idx)))
Array_Like_Helpers.any self condition
## GROUP Conversions
ICON convert

View File

@ -12,7 +12,6 @@ import project.Metadata.Widget
from project.Data.Boolean import Boolean, False, True
from project.Metadata import make_single_choice
from project.Metadata.Choice import Option
from project.Metadata.Widget import Multiple_Choice
## PRIVATE
Creates a Single_Choice Widget for text or secret value.
@ -25,22 +24,7 @@ make_text_secret_selector =
Creates a Regex / Text Widget for search and replace.
make_regex_text_widget : Widget
make_regex_text_widget =
options = Vector.build builder->
builder.append (Option "<Text Value>" '""')
builder.append (Option "<Regular Expression>" '(regex "^$")')
builder.append (Option "Leading_Whitespace" "Named_Pattern.Leading_Whitespace")
builder.append (Option "Trailing_Whitespace" "Named_Pattern.Trailing_Whitespace")
builder.append (Option "Duplicate_Whitespace" "Named_Pattern.Duplicate_Whitespace")
builder.append (Option "All_Whitespace" "Named_Pattern.All_Whitespace")
builder.append (Option "Leading_Numbers" "Named_Pattern.Leading_Numbers")
builder.append (Option "Trailing_Numbers" "Named_Pattern.Trailing_Numbers")
builder.append (Option "Non_ASCII" "Named_Pattern.Non_ASCII")
builder.append (Option "Tabs" "Named_Pattern.Tabs")
builder.append (Option "Letters" "Named_Pattern.Letters")
builder.append (Option "Numbers" "Named_Pattern.Numbers")
builder.append (Option "Punctuation" "Named_Pattern.Punctuation")
builder.append (Option "Symbols" "Named_Pattern.Symbols")
make_single_choice values=options
make_any_selector add_text=True add_regex=True add_named_pattern=True
## PRIVATE
Creates a Single_Choice Widget for delimiters.
@ -145,19 +129,22 @@ make_data_cleanse_vector_selector : Display -> Widget
make_data_cleanse_vector_selector display:Display=Display.Always =
patterns = ['Leading_Whitespace', 'Trailing_Whitespace', 'Duplicate_Whitespace', 'All_Whitespace', 'Leading_Numbers', 'Trailing_Numbers', 'Non_ASCII', 'Tabs', 'Letters', 'Numbers', 'Punctuation', 'Symbols']
options = patterns.map f-> Option f (".." + f)
Multiple_Choice values=options display=display
Widget.Multiple_Choice values=options display=display
## PRIVATE
Make a single value selector
make_any_selector : Display -> Boolean -> Boolean -> Boolean -> Boolean -> Boolean -> Boolean -> Widget
make_any_selector display:Display=..Always add_text:Boolean=False add_regex:Boolean=False add_number:Boolean=False add_boolean:Boolean=False add_named_pattern:Boolean=False add_nothing:Boolean=False =
text = if add_text then [Option "<Text Value>" "''"] else []
regex = if add_regex then [Option "<Regular Expression>" "(regex '')"] else []
number = if add_number then [Option "<Number Value>" "0"] else []
boolean = if add_boolean then [Option "<True/False>" "True"] else []
named_pattern = if add_named_pattern.not then [] else
patterns = ["Leading_Whitespace", "Trailing_Whitespace", "All_Whitespace", "Leading_Numbers", "Trailing_Numbers", "Non_ASCII", "Tabs", "Letters", "Numbers", "Punctuation", "Symbols"]
## Can't use auto-scoping as Named_Patterns are materialised into Regex.
patterns.map p-> Option "<"+p+">" "Named_Pattern."+p
nothing = if add_nothing then [Option "<Nothing>" "Nothing"] else []
make_single_choice (text + regex + number + boolean + named_pattern + nothing) display=display
Creates a Single_Choice Widget for Any selectors.
make_any_selector : Display -> Boolean -> Boolean -> Boolean -> Boolean -> Boolean -> Boolean -> Boolean -> Boolean -> Boolean -> Widget
make_any_selector display:Display=..Always add_text:Boolean=False add_regex:Boolean=False add_named_pattern:Boolean=False add_number:Boolean=False add_boolean:Boolean=False add_date:Boolean=False add_time:Boolean=False add_date_time:Boolean=False add_nothing:Boolean=False =
options = Vector.build builder->
if add_text then builder.append (Option "<Text Value>" '""')
if add_regex then builder.append (Option "<Regular Expression>" '(regex "^$")')
if add_named_pattern then
patterns = ["Leading_Whitespace", "Trailing_Whitespace", "All_Whitespace", "Leading_Numbers", "Trailing_Numbers", "Non_ASCII", "Tabs", "Letters", "Numbers", "Punctuation", "Symbols"]
patterns.each p-> builder.append (Option "<"+p+">" "Named_Pattern."+p)
if add_number then builder.append (Option "<Number Value>" "0")
if add_boolean then builder.append (Option "<True/False>" "True")
if add_date then builder.append (Option "<Date Value>" "(Date.new "+(Date.today.format "yyyy M d")+")")
if add_time then builder.append (Option "<Time Value>" "(Time_Of_Day.new "+(Time_Of_Day.now.format "H m s")+")")
if add_date_time then builder.append (Option "<Date Time Value>" "(Date_Time.new "+(Date_Time.now.format "yyyy M d H m s")+")")
if add_nothing then builder.append (Option "<Nothing>" "Nothing")
Widget.Single_Choice values=options display=display

View File

@ -1132,7 +1132,7 @@ type DB_Column
import Standard.Examples
example_fill_nothing = Examples.decimal_column.fill_nothing 20.5
@default (self-> Widget_Helpers.make_fill_default_value_selector add_number=(self.value_type.is_numeric || self.value_type==Value_Type.Mixed) add_boolean=(self.value_type.is_boolean || self.value_type==Value_Type.Mixed) add_text=(self.value_type.is_text || self.value_type==Value_Type.Mixed))
@default (self-> Widget_Helpers.make_fill_default_value_selector value_type=self.value_type)
fill_nothing : DB_Column | Previous_Value | Any -> DB_Column
fill_nothing self default =
if Previous_Value == default then Error.throw (Unsupported_Database_Operation.Error "The Previous_Value argument is currently not supported in the database backend.") else
@ -1161,7 +1161,7 @@ type DB_Column
import Standard.Examples
example_fill_empty = Examples.text_column_1.fill_empty "hello"
@default (Widget_Helpers.make_fill_default_value_selector add_text=True)
@default (self-> Widget_Helpers.make_fill_default_value_selector value_type=Value_Type.Char add_nothing=True)
fill_empty : DB_Column | Previous_Value | Any -> DB_Column
fill_empty self default =
if Previous_Value == default then Error.throw (Unsupported_Database_Operation.Error "The Previous_Value argument is currently not supported in the database backend.") else

View File

@ -44,6 +44,7 @@ import Standard.Table.Value_Type.By_Type
from Standard.Table import Aggregate_Column, Auto, Blank_Selector, Column_Ref, Data_Formatter, Join_Condition, Join_Kind, Match_Columns, Position, Previous_Value, Report_Unmatched, Set_Mode, Simple_Expression, Sort_Column, Table, Value_Type
from Standard.Table.Errors import all
from Standard.Table.Internal.Filter_Condition_Helpers import make_filter_column
from Standard.Table.Table import make_fill_nothing_default_widget
import project.Connection.Connection.Connection
import project.DB_Column.DB_Column
@ -167,7 +168,7 @@ type DB_Table
- if_missing: The value to use if the selector isn't present.
@selector Widget_Helpers.make_column_name_selector
@index (t-> Widget.Numeric_Input minimum=0 maximum=t.row_count-1)
@if_missing (make_any_selector add_text=True add_regex=True add_number=True add_boolean=True add_named_pattern=True add_nothing=True)
@if_missing (make_any_selector add_text=True add_regex=True add_number=True add_boolean=True add_named_pattern=True add_date=True add_time=True add_date_time=True add_nothing=True)
get_value : Text | Integer -> Integer -> Any -> Any
get_value self selector:(Text | Integer)=0 index:Integer=0 ~if_missing=Nothing =
col = self.get selector if_missing=Nothing
@ -2846,7 +2847,7 @@ type DB_Table
fill_nothing = table.fill_nothing ["col0", "col1"] 20.5
@columns (Widget_Helpers.make_column_name_multi_selector add_regex=True add_by_type=True)
@default (self -> Widget_Helpers.make_fill_default_value_selector column_source=self add_text=True add_number=True add_boolean=True)
@default make_fill_nothing_default_widget
fill_nothing : Vector (Integer | Text | Regex | By_Type) | Text | Integer | Regex | By_Type -> DB_Column | Column_Ref | Expression | Previous_Value | Any -> DB_Table
fill_nothing self (columns : Vector | Text | Integer | Regex | By_Type) default =
resolved_default = (self:Table_Ref).resolve default
@ -2874,7 +2875,7 @@ type DB_Table
fill_empty = table.fill_empty ["col0", "col1"] "hello"
@columns (Widget_Helpers.make_column_name_multi_selector add_regex=True add_by_type=True)
@default (self -> Widget_Helpers.make_fill_default_value_selector column_source=self add_text=True)
@default (self-> Widget_Helpers.make_fill_default_value_selector value_type=Value_Type.Char add_nothing=True)
fill_empty : Vector (Integer | Text | Regex | By_Type) | Text | Integer | Regex | By_Type -> DB_Column | Column_Ref | Expression | Previous_Value | Any -> DB_Table
fill_empty self (columns : Vector | Text | Integer | Regex | By_Type) default =
resolved_default = (self:Table_Ref).resolve default

View File

@ -1161,7 +1161,7 @@ type Column
import Standard.Examples
example_fill_nothing = Examples.decimal_column.fill_nothing 20.5
@default (self-> Widget_Helpers.make_fill_default_value_selector add_number=(self.value_type.is_numeric || self.value_type==Value_Type.Mixed) add_boolean=(self.value_type.is_boolean || self.value_type==Value_Type.Mixed) add_text=(self.value_type.is_text || self.value_type==Value_Type.Mixed))
@default (self-> Widget_Helpers.make_fill_default_value_selector value_type=self.value_type)
fill_nothing : Column | Previous_Value | Any -> Column
fill_nothing self default =
if Previous_Value == default then fill_previous self Nothing else
@ -1198,7 +1198,7 @@ type Column
import Standard.Examples
example_fill_empty = Examples.text_column_1.fill_empty "hello"
@default (Widget_Helpers.make_fill_default_value_selector add_text=True)
@default (self-> Widget_Helpers.make_fill_default_value_selector value_type=Value_Type.Char add_nothing=True)
fill_empty : Column | Previous_Value | Any -> Column
fill_empty self default =
Value_Type.expect_text self <|

View File

@ -83,8 +83,9 @@ type Table_Column_Helper
specified types will also be selected (i.e. ignore size, precision).
select_by_type : Vector Value_Type -> Boolean -> Vector
select_by_type self types:Vector strict:Boolean=False =
selected_columns = if strict then self.columns.filter c-> types.contains c.value_type else
self.columns.filter c-> types.any t-> c.value_type.is_same_type t
parsed_types = types.map t->t:Value_Type
selected_columns = if strict then self.columns.filter c-> parsed_types.contains c.value_type else
self.columns.filter c-> parsed_types.any t-> c.value_type.is_same_type t
if selected_columns.length == 0 then Error.throw (No_Output_Columns.Error "No columns of the specified types were found.") else
selected_columns

View File

@ -94,45 +94,36 @@ make_column_name_multi_selector table display:Display=Display.Always add_regex:B
## PRIVATE
Make a column reference by name selector.
make_column_ref_by_name_selector : Table -> Display -> Boolean -> Boolean -> Boolean -> Boolean -> Boolean -> Widget
make_column_ref_by_name_selector table display:Display=..Always add_text:Boolean=False add_regex:Boolean=False add_number:Boolean=False add_boolean:Boolean=False add_named_pattern:Boolean=False =
text = if add_text then [Option "<Text Value>" "''"] else []
regex = if add_regex then [Option "<Regular Expression>" "(regex '')"] else []
number = if add_number then [Option "<Number Value>" "0"] else []
boolean = if add_boolean then [Option "<True/False>" "True"] else []
named_pattern = if add_named_pattern.not then [] else
patterns = ["Leading_Whitespace", "Trailing_Whitespace", "All_Whitespace", "Leading_Numbers", "Trailing_Numbers", "Non_ASCII", "Tabs", "Letters", "Numbers", "Punctuation", "Symbols"]
## Can't use auto-scoping as Named_Patterns are materialised into Regex.
patterns.map p-> Option "<"+p+">" "Named_Pattern."+p
make_column_ref_by_name_selector table display:Display=..Always add_text:Boolean=False add_regex:Boolean=False add_number:Boolean=False add_boolean:Boolean=False add_named_pattern:Boolean=False add_date:Boolean=False add_time:Boolean=False add_date_time:Boolean=False add_nothing:Boolean=False =
constants = make_any_selector add_text=add_text add_regex=add_regex add_named_pattern=add_named_pattern add_number=add_number add_boolean=add_boolean add_date=add_date add_time=add_time add_date_time=add_date_time add_nothing=add_nothing . values
expression = if table.is_nothing then [] else [Option "<Expression>" "(expr '["+table.column_names.first+"]')"]
col_names = if table.is_nothing then [] else table.column_names.map (name -> Option name "(..Name "+name.pretty+")")
values = text + regex + number + boolean + named_pattern + expression + col_names
values = constants + expression + col_names
Single_Choice values=values display=display
## PRIVATE
If `column_source` is Nothing, `Column_Ref` options will not be added.
make_fill_default_value_selector : Table | Nothing -> Display -> Boolean -> Boolean -> Boolean -> Widget
make_fill_default_value_selector column_source=Nothing display=Display.Always add_text:Boolean=False add_number:Boolean=False add_boolean:Boolean=False =
column_ref = make_column_ref_by_name_selector column_source display add_text add_regex=False add_number=add_number add_boolean=add_boolean
make_fill_default_value_selector column_source=Nothing display:Display=..Always value_types=Value_Type.Mixed add_nothing:Boolean=False =
to_add = Types_To_Include.Value (Vector.unify_vector_or_element value_types)
column_ref = make_column_ref_by_name_selector column_source display add_text=to_add.text add_number=to_add.number add_boolean=to_add.boolean add_date=to_add.date add_time=to_add.time add_date_time=to_add.date_time add_nothing=add_nothing
previous_value = [Option 'Previous Value' 'Previous_Value']
Single_Choice values=(previous_value+column_ref.values) display=display
## PRIVATE
Make a filter condition selector.
make_filter_condition_selector : Table -> Display -> Widget
make_filter_condition_selector table display=Display.Always =
with_all_types = make_column_ref_by_name_selector table add_text=True add_number=True add_boolean=True
with_number_text = make_column_ref_by_name_selector table add_text=True add_number=True
equatable_types = make_column_ref_by_name_selector table add_text=True add_number=True add_boolean=True add_date=True add_time=True add_date_time=True
comparable_types = make_column_ref_by_name_selector table add_text=True add_number=True add_date=True add_time=True add_date_time=True
with_text = make_column_ref_by_name_selector table add_text=True
options = Vector.build builder->
builder.append (Option "Equals" "..Equal" [["to", with_all_types]])
builder.append (Option "Not Equals" "..Not_Equal" [["to", with_all_types]])
builder.append (Option "Less Than" "..Less" [["than", with_number_text]])
builder.append (Option "Less Than Or Equal" "..Equal_Or_Less" [["than", with_number_text]])
builder.append (Option "Greater Than" "..Greater" [["than", with_number_text]])
builder.append (Option "Greater Than Or Equal" "..Equal_Or_Greater" [["than", with_number_text]])
builder.append (Option "Between" "..Between" [["lower", with_number_text], ["upper", with_number_text]])
builder.append (Option "Equals" "..Equal" [["to", equatable_types]])
builder.append (Option "Not Equals" "..Not_Equal" [["to", equatable_types]])
builder.append (Option "Less Than" "..Less" [["than", comparable_types]])
builder.append (Option "Less Than Or Equal" "..Equal_Or_Less" [["than", comparable_types]])
builder.append (Option "Greater Than" "..Greater" [["than", comparable_types]])
builder.append (Option "Greater Than Or Equal" "..Equal_Or_Greater" [["than", comparable_types]])
builder.append (Option "Between" "..Between" [["lower", comparable_types], ["upper", comparable_types]])
builder.append (Option "Equals Ignore Case" "..Equal_Ignore_Case" [["to", with_text]])
builder.append (Option "Starts With" "..Starts_With" [["prefix", with_text]])
builder.append (Option "Ends With" "..Ends_With" [["suffix", with_text]])
@ -236,17 +227,40 @@ make_format_chooser_for_type value_type =
make_value_type_vector_selector : Widget
make_value_type_vector_selector =
meta = Meta.meta Value_Type
options = meta.constructors.map c-> Option c.name meta.qualified_name+"."+c.name
options = meta.constructors.map c-> Option c.name ".."+c.name
item_editor = Single_Choice display=Display.Always values=options
Vector_Editor item_editor=item_editor item_default="Value_Type.Boolean" display=Display.Always
Vector_Editor item_editor=item_editor item_default="..Boolean" display=Display.Always
## PRIVATE
Make a replace builder.
make_replace_selector : Display -> Widget
make_replace_selector display=Display.Always =
key_selector = make_any_selector add_text=True add_regex=True add_number=True add_boolean=True add_named_pattern=True add_nothing=False
value_selector = make_any_selector add_text=True add_regex=True add_number=True add_boolean=True add_named_pattern=True add_nothing=True
key_selector = make_any_selector add_text=True add_regex=True add_number=True add_boolean=True add_named_pattern=True add_date=True add_time=True add_date_time=True add_nothing=False
value_selector = make_any_selector add_text=True add_regex=True add_number=True add_boolean=True add_named_pattern=True add_date=True add_time=True add_date_time=True add_nothing=True
fqn = Meta.get_qualified_type_name Pair
name = Option "Pair" fqn+".Value" [["first", key_selector], ["second", value_selector]]
item_editor = Single_Choice display=Display.Always values=[name]
Vector_Editor item_editor=item_editor item_default="(Pair.Value 'Current' 'New')" display=display
## PRIVATE
type Types_To_Include
## PRIVATE
private Value types:Vector
## Are there any number columns?
number self = self.types.any value_type-> value_type.is_numeric || value_type==Value_Type.Mixed
## Are there any boolean columns?
boolean self = self.types.any value_type-> value_type.is_boolean || value_type==Value_Type.Mixed
## Are there any text columns?
text self = self.types.any value_type-> value_type.is_text || value_type==Value_Type.Mixed
## Are there any date columns?
date self = self.types.any value_type-> value_type.is_date || value_type==Value_Type.Mixed
## Are there any time columns?
time self = self.types.any value_type-> value_type.is_time || value_type==Value_Type.Mixed
## Are there any date_time columns?
date_time self = self.types.any value_type-> value_type.is_date_time || value_type==Value_Type.Mixed

View File

@ -5,7 +5,7 @@ import Standard.Base.Metadata.Display
import Standard.Base.Metadata.Widget
from Standard.Base.Metadata.Choice import Option
from Standard.Base.Metadata.Widget import Single_Choice
from Standard.Base.Widget_Helpers import make_format_chooser
from Standard.Base.Widget_Helpers import make_any_selector, make_format_chooser
import project.Column_Ref.Column_Ref
import project.Expression.Expression
@ -32,6 +32,10 @@ type Simple_Expression
input_column = table.resolve_as_column self.input
derived = case self.operation of
Simple_Calculation.Copy -> input_column . rename (input_column.name+" (Copy)")
Simple_Calculation.Text operation -> operation.evaluate input_column
Simple_Calculation.Math operation -> operation.evaluate input_column
Simple_Calculation.Date operation -> operation.evaluate input_column
Simple_Calculation.Logical operation -> operation.evaluate input_column
Simple_Calculation.Add rhs -> input_column + (table.resolve rhs)
Simple_Calculation.Subtract rhs -> input_column - (table.resolve rhs)
Simple_Calculation.Multiply rhs -> input_column * (table.resolve rhs)
@ -64,24 +68,117 @@ type Simple_Expression
Create a widget for operation
default_widget : Table_Ref -> Display -> Widget
default_widget table:Table_Ref display=Display.Always =
## Constants
text = Option "<Text Value>" "''"
number = Option "<Number Value>" "0"
boolean = Option "<True/False>" "True"
expression = Option "<Expression>" "(expr '["+table.column_names.first+"]')"
col_names = Widget_Helpers.make_column_ref_by_name_selector table
with_all_types = Widget_Helpers.make_column_ref_by_name_selector table add_text=True add_number=True add_boolean=True
with_number_text = Widget_Helpers.make_column_ref_by_name_selector table add_text=True add_number=True
with_number = Widget_Helpers.make_column_ref_by_name_selector table add_number=True
with_boolean = Widget_Helpers.make_column_ref_by_name_selector table add_boolean=True
with_text = Widget_Helpers.make_column_ref_by_name_selector table add_text=True
filter_cond = Widget_Helpers.make_filter_condition_selector table
options = Vector.build builder->
builder.append (Option "copy" "..Copy")
builder.append (Option "add" "..Add" [["rhs", with_number_text]])
builder.append (Option "format" "..Format" [["format", make_format_chooser include_number=True]])
builder.append (Option "if" "..If" [["condition", filter_cond], ["true_value", with_all_types], ["false_value", with_all_types]])
builder.append (Option "min" "..Min" [["rhs", with_number_text]])
builder.append (Option "max" "..Max" [["rhs", with_number_text]])
builder.append (Option "Text" "..Text" [["operation", Text_Operation.create_widget table]])
builder.append (Option "Math" "..Math" [["operation", Math_Operation.create_widget table]])
builder.append (Option "Date" "..Date" [["operation", Date_Operation.create_widget table]])
builder.append (Option "Logical" "..Logical" [["operation", Logical_Operation.create_widget table]])
## Constants
constants = make_any_selector add_text=True add_number=True add_boolean=True add_date=True add_time=True add_date_time=True . values
expression = Option "<Expression>" "(expr '["+table.column_names.first+"]')"
derived = Option "<Simple Expression>" "..Simple_Expr" [["input", with_all_types], ["operation", Single_Choice options]]
Single_Choice constants+[expression, derived] display=display
## Defines a set of Text based operations.
type Text_Operation
## Takes the first characters from the input column.
Left (length : Integer = 1)
## Takes the first characters from the input column.
Right (length : Integer = 1)
## Returns the character length of the input column.
Length
## Removes the specified characters, by default any whitespace, from the
start, the end, or both ends of the input.
Trim (where:Location=..Both) (what:Column_Ref|Expression|Text = "")
## Does the input start with the specified prefix.
Starts_With (prefix:Column_Ref|Expression|Text = "")
## Does the input end with the specified suffix.
Ends_With (suffix:Column_Ref|Expression|Text = "")
## Does the input contain the specified substring.
Contains (substring:Column_Ref|Expression|Text = "")
## PRIVATE
create_widget : Table_Ref -> Display -> Widget
create_widget table:Table_Ref display:Display=Display.Always =
with_number = Widget_Helpers.make_column_ref_by_name_selector table add_number=True
with_text = Widget_Helpers.make_column_ref_by_name_selector table add_text=True
options = Vector.build builder->
builder.append (Option "left" "..Left" [["length", with_number]])
builder.append (Option "right" "..Right" [["length", with_number]])
builder.append (Option "length" "..Length")
builder.append (Option "trim" "..Trim" [["what", with_text]])
builder.append (Option "starts_with" "..Starts_With" [["prefix", with_text]])
builder.append (Option "ends_with" "..Ends_With" [["suffix", with_text]])
builder.append (Option "contains" "..Contains" [["substring", with_text]])
Single_Choice options display=display
## PRIVATE
Evaluate the operation - will be passed a Column or DB_Column
evaluate : Any -> Any
evaluate self column =
case self of
Text_Operation.Left length -> column.text_left length
Text_Operation.Right length -> column.text_right length
Text_Operation.Length -> column.text_length
Text_Operation.Trim where what -> column.trim where what
Text_Operation.Starts_With prefix -> column.starts_with prefix
Text_Operation.Ends_With suffix -> column.ends_with suffix
Text_Operation.Contains substring -> column.contains substring
## Defines a set of Math based operations.
type Math_Operation
## Subtract two values/columns.
Subtract (rhs : Column_Ref|Expression|Number = 0)
## Multiply two values/columns.
Multiply (rhs : Column_Ref|Expression|Number = 1)
## Divide a fixed value or column by another value or column.
Divide (rhs : Column_Ref|Expression|Number = 1)
## Compute the remainder of a fixed value or column divided by another
value or column.
Mod (rhs : Column_Ref|Expression|Number = 1)
## Raise a fixed value or column to the power of another value or column.
Power (rhs : Column_Ref|Expression|Number = 1)
## Rounds values in the column to the specified precision.
Round (precision:Integer = 0) (use_bankers:Boolean = False)
## Rounds values in the column up to the nearest integer.
Ceil
## Rounds values in the column down to the nearest integer.
Floor
## Truncates the fractional part of values in the column.
Truncate
## PRIVATE
create_widget : Table_Ref -> Display -> Widget
create_widget table:Table_Ref display:Display=Display.Always =
with_number = Widget_Helpers.make_column_ref_by_name_selector table add_number=True
options = Vector.build builder->
builder.append (Option "subtract" "..Subtract" [["rhs", with_number]])
builder.append (Option "multiply" "..Multiply" [["rhs", with_number]])
builder.append (Option "divide" "..Divide" [["rhs", with_number]])
@ -91,30 +188,138 @@ type Simple_Expression
builder.append (Option "ceil" "..Ceil")
builder.append (Option "floor" "..Floor")
builder.append (Option "truncate" "..Truncate")
builder.append (Option "min" "..Min" [["rhs", with_number_text]])
builder.append (Option "max" "..Max" [["rhs", with_number_text]])
builder.append (Option "date add" "..Date_Add" [["length", with_number]])
builder.append (Option "date part" "..Date_Part")
builder.append (Option "date diff" "..Date_Diff" [["end", col_names]])
Single_Choice options display=display
## PRIVATE
Evaluate the operation - will be passed a Column or DB_Column
evaluate : Any -> Any
evaluate self column =
case self of
Math_Operation.Subtract rhs -> column - rhs
Math_Operation.Multiply rhs -> column * rhs
Math_Operation.Divide rhs -> column / rhs
Math_Operation.Mod rhs -> column % rhs
Math_Operation.Power rhs -> column ^ rhs
Math_Operation.Round precision use_bankers -> column.round precision use_bankers
Math_Operation.Ceil -> column.ceil
Math_Operation.Floor -> column.floor
Math_Operation.Truncate -> column.truncate
## Defines a set of Date based operations.
type Date_Operation
## Adds a period to a date/time column.
Add (length : Column_Ref|Expression|Integer = 1) (period : Date_Period|Time_Period = Date_Period.Day)
## Returns part of a date/time column.
Part (period : Date_Period|Time_Period = Date_Period.Day)
## Returns the difference between two date/time columns.
Diff (end : Column_Ref|Expression|Date_Time|Date|Time_Of_Day = Missing_Argument.throw "end") (period:Date_Period|Time_Period = Date_Period.Day)
## Removes the Time portion of a Date_Time column.
Truncate
## Returns the year of a Date or a Date_Time column.
Year
## Returns the month of a Date or a Date_Time column.
Month
## Returns the day of a Date or a Date_Time column.
Day
## Returns the hour of a Time or a Date_Time column.
Hour
## Returns the minute of a Time or a Date_Time column.
Minute
## Returns the second of a Time or a Date_Time column.
Second
## PRIVATE
create_widget : Table_Ref -> Display -> Widget
create_widget table:Table_Ref display:Display=Display.Always =
col_names = Widget_Helpers.make_column_ref_by_name_selector table
with_number = Widget_Helpers.make_column_ref_by_name_selector table add_number=True
options = Vector.build builder->
builder.append (Option "add" "..Date_Add" [["length", with_number]])
builder.append (Option "part" "..Date_Part")
builder.append (Option "diff" "..Date_Diff" [["end", col_names]])
builder.append (Option "truncate" "..Truncate")
builder.append (Option "year" "..Year")
builder.append (Option "month" "..Month")
builder.append (Option "day" "..Day")
builder.append (Option "hour" "..Hour")
builder.append (Option "minute" "..Minute")
builder.append (Option "second" "..Second")
Single_Choice options display=display
## PRIVATE
Evaluate the operation - will be passed a Column or DB_Column
evaluate : Any -> Any
evaluate self column =
case self of
Date_Operation.Add length period -> column.date_add length period
Date_Operation.Part period -> column.date_part period
Date_Operation.Diff end period -> column.date_diff end period
Date_Operation.Truncate -> column.truncate
Date_Operation.Year -> column.year
Date_Operation.Month -> column.month
Date_Operation.Day -> column.day
Date_Operation.Hour -> column.hour
Date_Operation.Minute -> column.minute
Date_Operation.Second -> column.second
## Defines a set of Logical based operations.
type Logical_Operation
## Negate a boolean column.
Not
## Boolean AND on two boolean columns.
And (rhs : Column_Ref|Expression|Boolean = True)
## Boolean OR on two boolean columns.
Or (rhs : Column_Ref|Expression|Boolean = False)
## PRIVATE
create_widget : Table_Ref -> Display -> Widget
create_widget table:Table_Ref display:Display=Display.Always =
with_boolean = Widget_Helpers.make_column_ref_by_name_selector table add_boolean=True
options = Vector.build builder->
builder.append (Option "not" "..Not")
builder.append (Option "and" "..And" [["rhs", with_boolean]])
builder.append (Option "or" "..Or" [["rhs", with_boolean]])
builder.append (Option "if" "..If" [["condition", filter_cond], ["true_value", with_all_types], ["false_value", with_all_types]])
builder.append (Option "trim" "..Trim" [["what", with_text]])
builder.append (Option "text_left" "..Text_Left" [["length", with_number]])
builder.append (Option "text_right" "..Text_Right" [["length", with_number]])
builder.append (Option "text_length" "..Text_Length")
builder.append (Option "format" "..Format" [["format", make_format_chooser include_number=True]])
Single_Choice options display=display
derived = Option "<Simple Expression>" "..Simple_Expr" [["input", with_all_types], ["operation", Single_Choice options]]
Single_Choice [text, number, boolean, expression, derived] display=display
## PRIVATE
Evaluate the operation - will be passed a Column or DB_Column
evaluate : Any -> Any
evaluate self column =
case self of
Logical_Operation.Not -> column.not
Logical_Operation.And rhs -> column && rhs
Logical_Operation.Or rhs -> column || rhs
## Defines the operation on a derived column.
type Simple_Calculation
## Creates a copy of the input column.
Copy
## Perform a Text Operation
Text (operation : Text_Operation = ..Left 1)
## Perform a Math Operation
Math (operation : Math_Operation = ..Subtract 0)
## Perform a Date Operation
Date (operation : Date_Operation = ..Date_Add 1)
## Perform a Logical Operation
Logical (operation : Logical_Operation = ..Not)
## Add two values/columns.
Add (rhs : Column_Ref|Expression|Number|Text = Missing_Argument.throw "rhs")
@ -172,7 +377,6 @@ type Simple_Calculation
Or (rhs : Column_Ref|Expression|Boolean = False)
## If input meets a condition return true value, otherwise false value.
The `true_value` and `false_value` can be either a constant or a column.
If (condition:Filter_Condition=(..Equal True)) (true_value:Column_Ref|Expression|Any = True) (false_value:Column_Ref|Expression|Any = False)

View File

@ -299,7 +299,7 @@ type Table
example_at = Examples.inventory_table.get_value "item_name" 4
@selector Widget_Helpers.make_column_name_selector
@index (t-> Widget.Numeric_Input minimum=0 maximum=t.row_count-1)
@if_missing (make_any_selector add_text=True add_regex=True add_number=True add_boolean=True add_named_pattern=True add_nothing=True)
@if_missing (make_any_selector add_text=True add_regex=True add_number=True add_boolean=True add_named_pattern=True add_date=True add_time=True add_date_time=True add_nothing=True)
get_value : Text | Integer -> Integer -> Any -> Any
get_value self selector:(Text | Integer)=0 index:Integer=0 ~if_missing=Nothing =
col = self.get selector if_missing=Nothing
@ -2897,7 +2897,7 @@ type Table
fill_nothing = table.fill_nothing ["col0", "col1"] 20.5
@columns (Widget_Helpers.make_column_name_multi_selector add_regex=True add_by_type=True)
@default (self -> Widget_Helpers.make_fill_default_value_selector column_source=self add_text=True add_number=True add_boolean=True)
@default make_fill_nothing_default_widget
fill_nothing : Vector (Integer | Text | Regex | By_Type) | Text | Integer | Regex | By_Type -> Column | Column_Ref | Expression | Previous_Value | Any -> Table
fill_nothing self (columns : Vector | Text | Integer | Regex | By_Type) default =
resolved_default = (self:Table_Ref).resolve default
@ -2925,7 +2925,7 @@ type Table
fill_empty = table.fill_empty ["col0", "col1"] "hello"
@columns (Widget_Helpers.make_column_name_multi_selector add_regex=True add_by_type=True)
@default (self -> Widget_Helpers.make_fill_default_value_selector column_source=self add_text=True)
@default (self-> Widget_Helpers.make_fill_default_value_selector value_type=Value_Type.Char add_nothing=True)
fill_empty : Vector (Integer | Text | Regex | By_Type) | Text | Integer | Regex | By_Type -> Column | Column_Ref | Expression | Previous_Value | Any -> Table
fill_empty self (columns : Vector | Text | Integer | Regex | By_Type) default =
resolved_default = (self:Table_Ref).resolve default
@ -3271,3 +3271,12 @@ Table.from (that:XML_Element) =
Either `Children` or `Value` will be generated, but not both.
Table.from (that:XML_Document) = Table.from that.root_element
## PRIVATE
make_fill_nothing_default_widget table cache=Nothing =
columns = cache.if_not_nothing <| cache "columns"
types = if columns.is_nothing then [Value_Type.Mixed] else
## (selectors:(Text | Integer | Regex | By_Type | Vector)) (case_sensitivity:Case_Sensitivity) (reorder:Boolean) (error_on_missing_columns:Boolean) (on_problems:Problem_Behavior) (error_on_empty:Boolean=True) =
real_columns = table.columns_helper.select_columns columns case_sensitivity=..Sensitive reorder=False error_on_missing_columns=False on_problems=..Ignore error_on_empty=False
if real_columns.length == 0 then [Value_Type.Mixed] else real_columns.map .value_type
Widget_Helpers.make_fill_default_value_selector table value_types=types

View File

@ -204,6 +204,22 @@ type Value_Type
Value_Type.Decimal _ _ -> True
_ -> False
## GROUP Standard.Base.Metadata
ICON metadata
Checks if the `Value_Type` represents a Date type.
is_date : Boolean
is_date self = case self of
Value_Type.Date -> True
_ -> False
## GROUP Standard.Base.Metadata
ICON metadata
Checks if the `Value_Type` represents a Time type.
is_time : Boolean
is_time self = case self of
Value_Type.Time -> True
_ -> False
## GROUP Standard.Base.Metadata
ICON metadata
Checks if the `Value_Type` represents a Date_Time type.

View File

@ -34,9 +34,9 @@ add_specs suite_builder = suite_builder.group "List" group_builder->
any_even.should_be_true
any_eq_five.should_be_false
l.any (Filter_Condition.Greater 1) . should_be_true
l.any (Filter_Condition.Less 0) . should_be_false
l.any (Filter_Condition.Equal_Or_Greater 1 Filter_Action.Remove) . should_be_false
l.any (..Greater 1) . should_be_true
l.any (..Less 0) . should_be_false
l.any (..Equal_Or_Greater 1 Filter_Action.Remove) . should_be_false
Test.expect_panic_with (l.any "invalid arg") Type_Error
@ -46,9 +46,9 @@ add_specs suite_builder = suite_builder.group "List" group_builder->
all_even . should_be_false
all_less_than_four . should_be_true
l.all (Filter_Condition.Greater 0) . should_be_true
l.all (Filter_Condition.Less 3) . should_be_false
l.any (Filter_Condition.Less 0 Filter_Action.Remove) . should_be_true
l.all (..Greater 0) . should_be_true
l.all (..Less 3) . should_be_false
l.any (..Less 0 Filter_Action.Remove) . should_be_true
Test.expect_panic_with (l.all "invalid arg") Type_Error
@ -71,8 +71,8 @@ add_specs suite_builder = suite_builder.group "List" group_builder->
empty.find (==1) . should_fail_with Not_Found
empty.find (==1) if_missing=Nothing . should_equal Nothing
l.find (Filter_Condition.Greater 1) . should_equal 2
l.find (Filter_Condition.Less 2 Filter_Action.Remove) . should_equal 2
l.find (..Greater 1) . should_equal 2
l.find (..Less 2 Filter_Action.Remove) . should_equal 2
Test.expect_panic_with (l.find "invalid arg") Type_Error
@ -92,8 +92,8 @@ add_specs suite_builder = suite_builder.group "List" group_builder->
l.index_of 2 start=-4 . should_fail_with Index_Out_Of_Bounds
l.index_of 2 start=-4 . should_fail_with Index_Out_Of_Bounds
l.index_of (Filter_Condition.Greater 1) . should_equal 1
l.index_of (Filter_Condition.Less 3 Filter_Action.Remove) . should_equal 2
l.index_of (..Greater 1) . should_equal 1
l.index_of (..Less 3 Filter_Action.Remove) . should_equal 2
l.index_of "invalid arg" . should_equal Nothing
group_builder.specify "should allow finding the last index of an element in the list with `.last_index_of`" <|
@ -112,9 +112,9 @@ add_specs suite_builder = suite_builder.group "List" group_builder->
ll.last_index_of 3 start=-7 . should_fail_with Index_Out_Of_Bounds
ll.last_index_of (==2) start=-2 . should_equal 4
ll.last_index_of (Filter_Condition.Greater 1) . should_equal 5
ll.last_index_of (Filter_Condition.Less 3) . should_equal 4
ll.last_index_of (Filter_Condition.Greater 2 Filter_Action.Remove) . should_equal 4
ll.last_index_of (..Greater 1) . should_equal 5
ll.last_index_of (..Less 3) . should_equal 4
ll.last_index_of (..Greater 2 Filter_Action.Remove) . should_equal 4
ll.last_index_of "invalid arg" . should_equal Nothing
group_builder.specify "should allow checking if the list is empty with `.is_empty`" <|
@ -133,82 +133,82 @@ add_specs suite_builder = suite_builder.group "List" group_builder->
group_builder.specify "should filter elements by Filter_Condition" <|
list = [1, 2, 3, 4, 5].to_list
list.filter (Filter_Condition.Greater than=3) . should_equal [4, 5].to_list
list.filter (Filter_Condition.Greater than=3 action=Filter_Action.Remove) . should_equal [1, 2, 3].to_list
list.filter (Filter_Condition.Less than=3.5) . should_equal [1, 2, 3].to_list
list.filter (Filter_Condition.Equal to=3) . should_equal (List.Cons 3 List.Nil)
list.filter (Filter_Condition.Not_Equal to=3) . should_equal [1, 2, 4, 5].to_list
list.filter (Filter_Condition.Equal_Or_Greater than=3) . should_equal [3, 4, 5].to_list
list.filter (Filter_Condition.Equal_Or_Less than=(-1)) . should_equal List.Nil
list.filter (Filter_Condition.Between 2 4) . should_equal [2, 3, 4].to_list
list.filter (Filter_Condition.Is_In [7, 3, 2]) . should_equal [2, 3].to_list
list.filter (..Greater than=3) . should_equal [4, 5].to_list
list.filter (..Greater than=3 action=Filter_Action.Remove) . should_equal [1, 2, 3].to_list
list.filter (..Less than=3.5) . should_equal [1, 2, 3].to_list
list.filter (..Equal to=3) . should_equal (List.Cons 3 List.Nil)
list.filter (..Not_Equal to=3) . should_equal [1, 2, 4, 5].to_list
list.filter (..Equal_Or_Greater than=3) . should_equal [3, 4, 5].to_list
list.filter (..Equal_Or_Less than=(-1)) . should_equal List.Nil
list.filter (..Between 2 4) . should_equal [2, 3, 4].to_list
list.filter (..Is_In [7, 3, 2]) . should_equal [2, 3].to_list
list.filter Filter_Condition.Is_Nothing . should_equal List.Nil
list.filter Filter_Condition.Not_Nothing . should_equal list
list.filter ..Is_Nothing . should_equal List.Nil
list.filter ..Not_Nothing . should_equal list
## Boolean based filters should fail with type error
Test.expect_panic Type_Error (list.filter Filter_Condition.Is_True)
Test.expect_panic Type_Error (list.filter Filter_Condition.Is_False)
Test.expect_panic Type_Error (list.filter ..Is_True)
Test.expect_panic Type_Error (list.filter ..Is_False)
## Text based filters should fail with type error
Test.expect_panic Type_Error (list.filter (Filter_Condition.Starts_With "a"))
Test.expect_panic Type_Error (list.filter (Filter_Condition.Ends_With "a"))
Test.expect_panic Type_Error (list.filter (Filter_Condition.Contains "a"))
Test.expect_panic Type_Error (list.filter (Filter_Condition.Equal_Ignore_Case "a"))
Test.expect_panic Type_Error (list.filter (Filter_Condition.Like "a%"))
Test.expect_panic Type_Error (list.filter Filter_Condition.Is_Empty)
Test.expect_panic Type_Error (list.filter Filter_Condition.Not_Empty)
Test.expect_panic Type_Error (list.filter (..Starts_With "a"))
Test.expect_panic Type_Error (list.filter (..Ends_With "a"))
Test.expect_panic Type_Error (list.filter (..Contains "a"))
Test.expect_panic Type_Error (list.filter (..Equal_Ignore_Case "a"))
Test.expect_panic Type_Error (list.filter (..Like "a%"))
Test.expect_panic Type_Error (list.filter ..Is_Empty)
Test.expect_panic Type_Error (list.filter ..Not_Empty)
txt = ["aaa", "bbb", "abab", "cccc", "baaa", "ś"].to_list
txt.filter (Filter_Condition.Contains "a") . should_equal ["aaa", "abab", "baaa"].to_list
txt.filter (Filter_Condition.Contains 'A' Case_Sensitivity.Sensitive) . should_equal [].to_list
txt.filter (Filter_Condition.Contains 'A' Case_Sensitivity.Insensitive) . should_equal ["aaa", "abab", "baaa"].to_list
txt.filter (Filter_Condition.Contains 's\u0301') . should_equal ["ś"].to_list
txt.filter (Filter_Condition.Contains 'S\u0301' Case_Sensitivity.Sensitive) . should_equal [].to_list
txt.filter (Filter_Condition.Contains 'S\u0301' Case_Sensitivity.Insensitive) . should_equal ["ś"].to_list
txt.filter (Filter_Condition.Starts_With "a") . should_equal ["aaa", "abab"].to_list
txt.filter (Filter_Condition.Starts_With "A" Case_Sensitivity.Sensitive) . should_equal [].to_list
txt.filter (Filter_Condition.Starts_With "A" Case_Sensitivity.Insensitive) . should_equal ["aaa", "abab"].to_list
txt.filter (Filter_Condition.Ends_With "a") . should_equal ["aaa", "baaa"].to_list
txt.filter (Filter_Condition.Ends_With "A" Case_Sensitivity.Sensitive) . should_equal [].to_list
txt.filter (Filter_Condition.Ends_With "A" Case_Sensitivity.Insensitive) . should_equal ["aaa", "baaa"].to_list
txt.filter (Filter_Condition.Less than="a") . should_equal List.Nil
txt.filter (Filter_Condition.Greater than="b") . should_equal ["bbb", "cccc", "baaa", "ś"].to_list
txt.filter (Filter_Condition.Between "b" "c") . should_equal ["bbb", "baaa"].to_list
Test.expect_panic_with (txt.filter (Filter_Condition.Starts_With 42)) Unsupported_Argument_Types
txt.filter (..Contains "a") . should_equal ["aaa", "abab", "baaa"].to_list
txt.filter (..Contains 'A' Case_Sensitivity.Sensitive) . should_equal [].to_list
txt.filter (..Contains 'A' Case_Sensitivity.Insensitive) . should_equal ["aaa", "abab", "baaa"].to_list
txt.filter (..Contains 's\u0301') . should_equal ["ś"].to_list
txt.filter (..Contains 'S\u0301' Case_Sensitivity.Sensitive) . should_equal [].to_list
txt.filter (..Contains 'S\u0301' Case_Sensitivity.Insensitive) . should_equal ["ś"].to_list
txt.filter (..Starts_With "a") . should_equal ["aaa", "abab"].to_list
txt.filter (..Starts_With "A" Case_Sensitivity.Sensitive) . should_equal [].to_list
txt.filter (..Starts_With "A" Case_Sensitivity.Insensitive) . should_equal ["aaa", "abab"].to_list
txt.filter (..Ends_With "a") . should_equal ["aaa", "baaa"].to_list
txt.filter (..Ends_With "A" Case_Sensitivity.Sensitive) . should_equal [].to_list
txt.filter (..Ends_With "A" Case_Sensitivity.Insensitive) . should_equal ["aaa", "baaa"].to_list
txt.filter (..Less than="a") . should_equal List.Nil
txt.filter (..Greater than="b") . should_equal ["bbb", "cccc", "baaa", "ś"].to_list
txt.filter (..Between "b" "c") . should_equal ["bbb", "baaa"].to_list
Test.expect_panic_with (txt.filter (..Starts_With 42)) Unsupported_Argument_Types
["", Nothing, " ", "a"].to_list.filter (Filter_Condition.Is_Empty) . should_equal ["", Nothing].to_list
["", Nothing, " ", "a"].to_list.filter (Filter_Condition.Not_Empty) . should_equal [" ", "a"].to_list
["abab", "aaabaaaa", "ba"].to_list.filter (Filter_Condition.Like "ba") . should_equal (List.Cons "ba" List.Nil)
["abab", "aaabaaaa"].to_list.filter (Filter_Condition.Like "_ba_") . should_equal ["abab"].to_list
["abab", "aaabaaaa"].to_list.filter (Filter_Condition.Like "%ba__%") . should_equal ["aaabaaaa"].to_list
["", Nothing, " ", "a"].to_list.filter (..Is_Empty) . should_equal ["", Nothing].to_list
["", Nothing, " ", "a"].to_list.filter (..Not_Empty) . should_equal [" ", "a"].to_list
["abab", "aaabaaaa", "ba"].to_list.filter (..Like "ba") . should_equal (List.Cons "ba" List.Nil)
["abab", "aaabaaaa"].to_list.filter (..Like "_ba_") . should_equal ["abab"].to_list
["abab", "aaabaaaa"].to_list.filter (..Like "%ba__%") . should_equal ["aaabaaaa"].to_list
mixed = [1, Nothing, "b"].to_list
mixed.filter Filter_Condition.Is_Nothing . should_equal (List.Cons Nothing List.Nil)
mixed.filter Filter_Condition.Not_Nothing . should_equal (List.Cons 1 (List.Cons "b" List.Nil))
mixed.filter ..Is_Nothing . should_equal (List.Cons Nothing List.Nil)
mixed.filter ..Not_Nothing . should_equal (List.Cons 1 (List.Cons "b" List.Nil))
bools = [True, False, Nothing, True].to_list
bools.filter Filter_Condition.Is_True . should_equal [True, True].to_list
bools.filter Filter_Condition.Is_False . should_equal [False].to_list
bools.filter ..Is_True . should_equal [True, True].to_list
bools.filter ..Is_False . should_equal [False].to_list
group_builder.specify "should allow to partition a list" <|
r1 = l.partition (x-> x%2==0)
r1.first . should_equal (List.Cons 2 List.Nil)
r1.second . should_equal (List.Cons 1 (List.Cons 3 List.Nil))
r2 = l.partition (Filter_Condition.Greater than=1)
r2 = l.partition (..Greater than=1)
r2.first . should_equal (List.Cons 2 (List.Cons 3 List.Nil))
r2.second . should_equal (List.Cons 1 List.Nil)
r2r = l.partition (Filter_Condition.Greater than=1 action=Filter_Action.Remove)
r2r = l.partition (..Greater than=1 action=Filter_Action.Remove)
r2r.second . should_equal (List.Cons 2 (List.Cons 3 List.Nil))
r2r.first . should_equal (List.Cons 1 List.Nil)
r3 = l.partition (Filter_Condition.Equal_Or_Greater than=10)
r3 = l.partition (..Equal_Or_Greater than=10)
r3.first . should_equal List.Nil
r3.second . should_equal l
r4 = l.partition (Filter_Condition.Less than=10)
r4 = l.partition (..Less than=10)
r4.first . should_equal l
r4.second . should_equal List.Nil

View File

@ -153,48 +153,48 @@ add_specs suite_builder = suite_builder.group "Range" group_builder->
group_builder.specify "should filter elements by Filter_Condition" <|
range = 1.up_to 6
range.filter (Filter_Condition.Greater 3) . should_equal [4, 5]
range.filter (Filter_Condition.Greater 3 Filter_Action.Remove) . should_equal [1, 2, 3]
range.filter (Filter_Condition.Less 3.5) . should_equal [1, 2, 3]
range.filter (Filter_Condition.Less 3.5 Filter_Action.Remove) . should_equal [4, 5]
range.filter (Filter_Condition.Equal 3) . should_equal [3]
range.filter (Filter_Condition.Equal 3 Filter_Action.Remove) . should_equal [1, 2, 4, 5]
range.filter (Filter_Condition.Not_Equal 3) . should_equal [1, 2, 4, 5]
range.filter (Filter_Condition.Not_Equal 3 Filter_Action.Remove) . should_equal [3]
range.filter (Filter_Condition.Equal_Or_Greater 3) . should_equal [3, 4, 5]
range.filter (Filter_Condition.Equal_Or_Greater 3 Filter_Action.Remove) . should_equal [1, 2]
range.filter (Filter_Condition.Equal_Or_Less (-1)) . should_equal []
range.filter (Filter_Condition.Equal_Or_Less (-1) Filter_Action.Remove) . should_equal [1, 2, 3, 4, 5]
range.filter (Filter_Condition.Between 2 4) . should_equal [2, 3, 4]
range.filter (Filter_Condition.Between 2.1 4.5) . should_equal [3, 4]
range.filter (Filter_Condition.Between 2 4 Filter_Action.Remove) . should_equal [1, 5]
range.filter (Filter_Condition.Is_In [7, 3, 2]) . should_equal [2, 3]
range.filter (Filter_Condition.Is_In [7, 3, 2] Filter_Action.Remove) . should_equal [1, 4, 5]
range.filter (..Greater 3) . should_equal [4, 5]
range.filter (..Greater 3 Filter_Action.Remove) . should_equal [1, 2, 3]
range.filter (..Less 3.5) . should_equal [1, 2, 3]
range.filter (..Less 3.5 Filter_Action.Remove) . should_equal [4, 5]
range.filter (..Equal 3) . should_equal [3]
range.filter (..Equal 3 Filter_Action.Remove) . should_equal [1, 2, 4, 5]
range.filter (..Not_Equal 3) . should_equal [1, 2, 4, 5]
range.filter (..Not_Equal 3 Filter_Action.Remove) . should_equal [3]
range.filter (..Equal_Or_Greater 3) . should_equal [3, 4, 5]
range.filter (..Equal_Or_Greater 3 Filter_Action.Remove) . should_equal [1, 2]
range.filter (..Equal_Or_Less (-1)) . should_equal []
range.filter (..Equal_Or_Less (-1) Filter_Action.Remove) . should_equal [1, 2, 3, 4, 5]
range.filter (..Between 2 4) . should_equal [2, 3, 4]
range.filter (..Between 2.1 4.5) . should_equal [3, 4]
range.filter (..Between 2 4 Filter_Action.Remove) . should_equal [1, 5]
range.filter (..Is_In [7, 3, 2]) . should_equal [2, 3]
range.filter (..Is_In [7, 3, 2] Filter_Action.Remove) . should_equal [1, 4, 5]
range.filter Filter_Condition.Is_Nan . should_equal []
range.filter (Filter_Condition.Is_Nan Filter_Action.Remove) . should_equal [1, 2, 3, 4, 5]
range.filter Filter_Condition.Is_Infinite . should_equal []
range.filter (Filter_Condition.Is_Infinite Filter_Action.Remove) . should_equal [1, 2, 3, 4, 5]
range.filter Filter_Condition.Is_Finite . should_equal [1, 2, 3, 4, 5]
range.filter (Filter_Condition.Is_Finite Filter_Action.Remove) . should_equal []
range.filter ..Is_Nan . should_equal []
range.filter (..Is_Nan Filter_Action.Remove) . should_equal [1, 2, 3, 4, 5]
range.filter ..Is_Infinite . should_equal []
range.filter (..Is_Infinite Filter_Action.Remove) . should_equal [1, 2, 3, 4, 5]
range.filter ..Is_Finite . should_equal [1, 2, 3, 4, 5]
range.filter (..Is_Finite Filter_Action.Remove) . should_equal []
range.filter Filter_Condition.Is_Nothing . should_equal []
range.filter (Filter_Condition.Is_Nothing Filter_Action.Remove) . should_equal [1, 2, 3, 4, 5]
range.filter Filter_Condition.Not_Nothing . should_equal [1, 2, 3, 4, 5]
range.filter (Filter_Condition.Not_Nothing Filter_Action.Remove) . should_equal []
range.filter ..Is_Nothing . should_equal []
range.filter (..Is_Nothing Filter_Action.Remove) . should_equal [1, 2, 3, 4, 5]
range.filter ..Not_Nothing . should_equal [1, 2, 3, 4, 5]
range.filter (..Not_Nothing Filter_Action.Remove) . should_equal []
## Text based filters should fail with type error
Test.expect_panic Type_Error (range.filter (Filter_Condition.Starts_With "a"))
Test.expect_panic Type_Error (range.filter (Filter_Condition.Ends_With "a"))
Test.expect_panic Type_Error (range.filter (Filter_Condition.Contains "a"))
Test.expect_panic Type_Error (range.filter (Filter_Condition.Equal_Ignore_Case "a"))
Test.expect_panic Type_Error (range.filter (Filter_Condition.Like "a%"))
Test.expect_panic Type_Error (range.filter Filter_Condition.Is_Empty)
Test.expect_panic Type_Error (range.filter Filter_Condition.Not_Empty)
Test.expect_panic Type_Error (range.filter (..Starts_With "a"))
Test.expect_panic Type_Error (range.filter (..Ends_With "a"))
Test.expect_panic Type_Error (range.filter (..Contains "a"))
Test.expect_panic Type_Error (range.filter (..Equal_Ignore_Case "a"))
Test.expect_panic Type_Error (range.filter (..Like "a%"))
Test.expect_panic Type_Error (range.filter ..Is_Empty)
Test.expect_panic Type_Error (range.filter ..Not_Empty)
## Boolean based filters should fail with type error
Test.expect_panic Type_Error (range.filter Filter_Condition.Is_True)
Test.expect_panic Type_Error (range.filter Filter_Condition.Is_False)
Test.expect_panic Type_Error (range.filter ..Is_True)
Test.expect_panic Type_Error (range.filter ..Is_False)
group_builder.specify "should allow to partition its elements" <|
elements = 0.up_to 10
@ -202,11 +202,11 @@ add_specs suite_builder = suite_builder.group "Range" group_builder->
r1.first . should_equal [0, 2, 4, 6, 8]
r1.second . should_equal [1, 3, 5, 7, 9]
r2 = elements.partition (Filter_Condition.Greater 3)
r2 = elements.partition (..Greater 3)
r2.first . should_equal [4, 5, 6, 7, 8, 9]
r2.second . should_equal [0, 1, 2, 3]
r2r = elements.partition (Filter_Condition.Greater 3 Filter_Action.Remove)
r2r = elements.partition (..Greater 3 Filter_Action.Remove)
r2r.first . should_equal [0, 1, 2, 3]
r2r.second . should_equal [4, 5, 6, 7, 8, 9]
@ -251,21 +251,21 @@ add_specs suite_builder = suite_builder.group "Range" group_builder->
group_builder.specify "should check all" <|
1.up_to 10 . all (> 0) . should_be_true
1.up_to 10 . all (< 0) . should_be_false
1.up_to 10 . all (Filter_Condition.Greater 10) . should_be_false
1.up_to 10 . all (Filter_Condition.Greater 10 Filter_Action.Remove) . should_be_true
1.up_to 10 . all (..Greater 10) . should_be_false
1.up_to 10 . all (..Greater 10 Filter_Action.Remove) . should_be_true
Test.expect_panic_with (1.up_to 10 . all "invalid arg") Type_Error
group_builder.specify "should check any" <|
1.up_to 10 . any (> 5) . should_be_true
1.up_to 10 . any (> 10) . should_be_false
1.up_to 10 . any (Filter_Condition.Greater 5) . should_be_true
1.up_to 10 . any (Filter_Condition.Equal_Or_Greater 1 Filter_Action.Remove) . should_be_false
1.up_to 10 . any (..Greater 5) . should_be_true
1.up_to 10 . any (..Equal_Or_Greater 1 Filter_Action.Remove) . should_be_false
Test.expect_panic_with (1.up_to 10 . any "invalid arg") Type_Error
group_builder.specify "should find elements" <|
1.up_to 10 . find (> 5) . should_equal 6
1.up_to 10 . find (Filter_Condition.Greater 5) . should_equal 6
1.up_to 10 . find (Filter_Condition.Equal_Or_Less 3 Filter_Action.Remove) . should_equal 4
1.up_to 10 . find (..Greater 5) . should_equal 6
1.up_to 10 . find (..Equal_Or_Less 3 Filter_Action.Remove) . should_equal 4
1.up_to 10 . find (> 10) . should_be_a Nothing
1.up_to 10 . find (v-> v%4 == 0) start=6 . should_equal 8
1.up_to 10 . find (< 5) start=6 . should_be_a Nothing
@ -288,8 +288,8 @@ add_specs suite_builder = suite_builder.group "Range" group_builder->
1.up_to 10 . index_of (< 5) start=10 . catch . should_equal (Index_Out_Of_Bounds.Error 10 10)
1.up_to 10 . index_of (< 5) start=-1 . should_equal Nothing
1.up_to 10 . index_of (< 5) start=-9 . should_equal 0
1.up_to 10 . index_of (Filter_Condition.Greater 5) . should_equal 5
1.up_to 10 . index_of (Filter_Condition.Less 5 Filter_Action.Remove) . should_equal 4
1.up_to 10 . index_of (..Greater 5) . should_equal 5
1.up_to 10 . index_of (..Less 5 Filter_Action.Remove) . should_equal 4
1.up_to 10 . index_of "invalid arg" . should_fail_with Illegal_Argument
1.up_to 10 . index_of 2.5 . should_fail_with Illegal_Argument
@ -308,8 +308,8 @@ add_specs suite_builder = suite_builder.group "Range" group_builder->
1.up_to 10 . last_index_of (< 5) start=9 . should_fail_with Index_Out_Of_Bounds
1.up_to 10 . last_index_of (< 5) start=10 . catch . should_equal (Index_Out_Of_Bounds.Error 10 9)
1.up_to 10 . last_index_of (< 5) start=-10 . should_fail_with Index_Out_Of_Bounds
1.up_to 10 . last_index_of (Filter_Condition.Greater 5) . should_equal 8
1.up_to 10 . last_index_of (Filter_Condition.Greater 5 Filter_Action.Remove) . should_equal 4
1.up_to 10 . last_index_of (..Greater 5) . should_equal 8
1.up_to 10 . last_index_of (..Greater 5 Filter_Action.Remove) . should_equal 4
1.up_to 10 . last_index_of "invalid arg" . should_fail_with Illegal_Argument
1.up_to 10 . last_index_of 2.5 . should_fail_with Illegal_Argument

View File

@ -168,10 +168,10 @@ type_spec suite_builder name alter = suite_builder.group name group_builder->
vec.any (ix -> ix > 3) . should_be_true
vec.any (ix -> ix < 0) . should_be_false
vec.any (Filter_Condition.Greater 0) . should_be_true
vec.any (Filter_Condition.Greater 0 Filter_Action.Remove) . should_be_false
vec.any (Filter_Condition.Less 3) . should_be_true
vec.any (Filter_Condition.Less 0) . should_be_false
vec.any (..Greater 0) . should_be_true
vec.any (..Greater 0 Filter_Action.Remove) . should_be_false
vec.any (..Less 3) . should_be_true
vec.any (..Less 0) . should_be_false
Test.expect_panic_with matcher=Type_Error (vec.any "invalid argument")
@ -180,9 +180,9 @@ type_spec suite_builder name alter = suite_builder.group name group_builder->
vec.all (ix -> ix > 0) . should_be_true
vec.all (ix -> ix < 5) . should_be_false
vec.all (Filter_Condition.Greater 0) . should_be_true
vec.all (Filter_Condition.Greater 0 Filter_Action.Remove) . should_be_false
vec.all (Filter_Condition.Less 3) . should_be_false
vec.all (..Greater 0) . should_be_true
vec.all (..Greater 0 Filter_Action.Remove) . should_be_false
vec.all (..Less 3) . should_be_false
Test.expect_panic_with matcher=Type_Error (vec.all "invalid argument")
@ -212,159 +212,159 @@ type_spec suite_builder name alter = suite_builder.group name group_builder->
group_builder.specify "should filter numerical elements by Filter_Condition" <|
vec = alter [1, 2, 3, 4, 5]
vec.filter (Filter_Condition.Greater 3) . should_equal [4, 5]
vec.filter (Filter_Condition.Greater 3 Filter_Action.Remove) . should_equal [1, 2, 3]
vec.filter (Filter_Condition.Less 3.5) . should_equal [1, 2, 3]
vec.filter (Filter_Condition.Less 3.5 Filter_Action.Remove) . should_equal [4, 5]
vec.filter (Filter_Condition.Equal 3) . should_equal [3]
vec.filter (Filter_Condition.Equal 3 Filter_Action.Remove) . should_equal [1, 2, 4, 5]
vec.filter (Filter_Condition.Not_Equal 3) . should_equal [1, 2, 4, 5]
vec.filter (Filter_Condition.Not_Equal 3 Filter_Action.Remove) . should_equal [3]
vec.filter (Filter_Condition.Equal_Or_Greater 3) . should_equal [3, 4, 5]
vec.filter (Filter_Condition.Equal_Or_Greater 3 Filter_Action.Remove) . should_equal [1, 2]
vec.filter (Filter_Condition.Equal_Or_Less (-1)) . should_equal []
vec.filter (Filter_Condition.Equal_Or_Less (-1) Filter_Action.Remove) . should_equal [1, 2, 3, 4, 5]
vec.filter (Filter_Condition.Between 2 4) . should_equal [2, 3, 4]
vec.filter (Filter_Condition.Between 2.1 4.5) . should_equal [3, 4]
vec.filter (Filter_Condition.Between 2 4 Filter_Action.Remove) . should_equal [1, 5]
vec.filter (Filter_Condition.Is_In [7, 3, 2, 2, 2]) . should_equal [2, 3]
vec.filter (Filter_Condition.Is_In [7, 3, 2] Filter_Action.Remove) . should_equal [1, 4, 5]
vec.filter (..Greater 3) . should_equal [4, 5]
vec.filter (..Greater 3 Filter_Action.Remove) . should_equal [1, 2, 3]
vec.filter (..Less 3.5) . should_equal [1, 2, 3]
vec.filter (..Less 3.5 Filter_Action.Remove) . should_equal [4, 5]
vec.filter (..Equal 3) . should_equal [3]
vec.filter (..Equal 3 Filter_Action.Remove) . should_equal [1, 2, 4, 5]
vec.filter (..Not_Equal 3) . should_equal [1, 2, 4, 5]
vec.filter (..Not_Equal 3 Filter_Action.Remove) . should_equal [3]
vec.filter (..Equal_Or_Greater 3) . should_equal [3, 4, 5]
vec.filter (..Equal_Or_Greater 3 Filter_Action.Remove) . should_equal [1, 2]
vec.filter (..Equal_Or_Less (-1)) . should_equal []
vec.filter (..Equal_Or_Less (-1) Filter_Action.Remove) . should_equal [1, 2, 3, 4, 5]
vec.filter (..Between 2 4) . should_equal [2, 3, 4]
vec.filter (..Between 2.1 4.5) . should_equal [3, 4]
vec.filter (..Between 2 4 Filter_Action.Remove) . should_equal [1, 5]
vec.filter (..Is_In [7, 3, 2, 2, 2]) . should_equal [2, 3]
vec.filter (..Is_In [7, 3, 2] Filter_Action.Remove) . should_equal [1, 4, 5]
vec.filter Filter_Condition.Is_Nothing . should_equal []
vec.filter (Filter_Condition.Is_Nothing Filter_Action.Remove) . should_equal [1, 2, 3, 4, 5]
vec.filter Filter_Condition.Not_Nothing . should_equal [1, 2, 3, 4, 5]
vec.filter (Filter_Condition.Not_Nothing Filter_Action.Remove) . should_equal []
vec.filter ..Is_Nothing . should_equal []
vec.filter (..Is_Nothing Filter_Action.Remove) . should_equal [1, 2, 3, 4, 5]
vec.filter ..Not_Nothing . should_equal [1, 2, 3, 4, 5]
vec.filter (..Not_Nothing Filter_Action.Remove) . should_equal []
numvec = alter [1, 2.5, Number.nan, Number.positive_infinity, Number.negative_infinity, 0]
# We need to use to_text because NaN!=NaN
numvec.filter Filter_Condition.Is_Nan . map .to_text . should_equal ["NaN"]
numvec.filter (Filter_Condition.Is_Nan Filter_Action.Remove) . should_equal [1, 2.5, Number.positive_infinity, Number.negative_infinity, 0]
numvec.filter Filter_Condition.Is_Infinite . should_equal [Number.positive_infinity, Number.negative_infinity]
numvec.filter (Filter_Condition.Is_Infinite Filter_Action.Remove) . length . should_equal 4
numvec.filter Filter_Condition.Is_Finite . should_equal [1, 2.5, 0]
numvec.filter (Filter_Condition.Is_Finite Filter_Action.Remove) . length . should_equal 3
numvec.filter ..Is_Nan . map .to_text . should_equal ["NaN"]
numvec.filter (..Is_Nan Filter_Action.Remove) . should_equal [1, 2.5, Number.positive_infinity, Number.negative_infinity, 0]
numvec.filter ..Is_Infinite . should_equal [Number.positive_infinity, Number.negative_infinity]
numvec.filter (..Is_Infinite Filter_Action.Remove) . length . should_equal 4
numvec.filter ..Is_Finite . should_equal [1, 2.5, 0]
numvec.filter (..Is_Finite Filter_Action.Remove) . length . should_equal 3
## Text based filters should fail with type error
Test.expect_panic Type_Error (vec.filter (Filter_Condition.Starts_With "a"))
Test.expect_panic Type_Error (vec.filter (Filter_Condition.Ends_With "a"))
Test.expect_panic Type_Error (vec.filter (Filter_Condition.Contains "a"))
Test.expect_panic Type_Error (vec.filter (Filter_Condition.Equal_Ignore_Case "a"))
Test.expect_panic Type_Error (vec.filter (Filter_Condition.Like "a%"))
Test.expect_panic Type_Error (vec.filter Filter_Condition.Is_Empty)
Test.expect_panic Type_Error (vec.filter Filter_Condition.Not_Empty)
Test.expect_panic Type_Error (vec.filter (..Starts_With "a"))
Test.expect_panic Type_Error (vec.filter (..Ends_With "a"))
Test.expect_panic Type_Error (vec.filter (..Contains "a"))
Test.expect_panic Type_Error (vec.filter (..Equal_Ignore_Case "a"))
Test.expect_panic Type_Error (vec.filter (..Like "a%"))
Test.expect_panic Type_Error (vec.filter ..Is_Empty)
Test.expect_panic Type_Error (vec.filter ..Not_Empty)
## Boolean based filters should fail with type error
Test.expect_panic Type_Error (vec.filter Filter_Condition.Is_True)
Test.expect_panic Type_Error (vec.filter Filter_Condition.Is_False)
Test.expect_panic Type_Error (vec.filter ..Is_True)
Test.expect_panic Type_Error (vec.filter ..Is_False)
group_builder.specify "should filter text elements by Filter_Condition" <|
group_builder.specify "should filter text elements by ." <|
txtvec = alter ["aaa", "bbb", "abab", "cccc", "baaa", "ś"]
txtvec.filter (Filter_Condition.Contains "a") . should_equal ["aaa", "abab", "baaa"]
txtvec.filter (Filter_Condition.Contains "a" action=Filter_Action.Remove) . should_equal ["bbb", "cccc", "ś"]
txtvec.filter (Filter_Condition.Contains 'A' Case_Sensitivity.Sensitive) . should_equal []
txtvec.filter (Filter_Condition.Contains 'A' Case_Sensitivity.Insensitive) . should_equal ["aaa", "abab", "baaa"]
txtvec.filter (Filter_Condition.Contains 's\u0301') . should_equal ["ś"]
txtvec.filter (Filter_Condition.Contains 'S\u0301' Case_Sensitivity.Sensitive) . should_equal []
txtvec.filter (Filter_Condition.Contains 'S\u0301' Case_Sensitivity.Insensitive) . should_equal ["ś"]
Test.expect_panic_with (txtvec.filter (Filter_Condition.Contains 42)) Unsupported_Argument_Types
txtvec.filter (Filter_Condition.Starts_With "a") . should_equal ["aaa", "abab"]
txtvec.filter (Filter_Condition.Starts_With "a" action=Filter_Action.Remove) . should_equal ["bbb", "cccc", "baaa", "ś"]
txtvec.filter (Filter_Condition.Starts_With "A" Case_Sensitivity.Sensitive) . should_equal []
txtvec.filter (Filter_Condition.Starts_With "A" Case_Sensitivity.Insensitive) . should_equal ["aaa", "abab"]
Test.expect_panic_with (txtvec.filter (Filter_Condition.Starts_With 42)) Unsupported_Argument_Types
txtvec.filter (Filter_Condition.Ends_With "a") . should_equal ["aaa", "baaa"]
txtvec.filter (Filter_Condition.Ends_With "a" action=Filter_Action.Remove) . should_equal ["bbb", "abab", "cccc", "ś"]
txtvec.filter (Filter_Condition.Ends_With "A" Case_Sensitivity.Sensitive) . should_equal []
txtvec.filter (Filter_Condition.Ends_With "A" Case_Sensitivity.Insensitive) . should_equal ["aaa", "baaa"]
Test.expect_panic_with (txtvec.filter (Filter_Condition.Ends_With 42)) Unsupported_Argument_Types
txtvec.filter (..Contains "a") . should_equal ["aaa", "abab", "baaa"]
txtvec.filter (..Contains "a" action=Filter_Action.Remove) . should_equal ["bbb", "cccc", "ś"]
txtvec.filter (..Contains 'A' Case_Sensitivity.Sensitive) . should_equal []
txtvec.filter (..Contains 'A' Case_Sensitivity.Insensitive) . should_equal ["aaa", "abab", "baaa"]
txtvec.filter (..Contains 's\u0301') . should_equal ["ś"]
txtvec.filter (..Contains 'S\u0301' Case_Sensitivity.Sensitive) . should_equal []
txtvec.filter (..Contains 'S\u0301' Case_Sensitivity.Insensitive) . should_equal ["ś"]
Test.expect_panic_with (txtvec.filter (..Contains 42)) Unsupported_Argument_Types
txtvec.filter (..Starts_With "a") . should_equal ["aaa", "abab"]
txtvec.filter (..Starts_With "a" action=Filter_Action.Remove) . should_equal ["bbb", "cccc", "baaa", "ś"]
txtvec.filter (..Starts_With "A" Case_Sensitivity.Sensitive) . should_equal []
txtvec.filter (..Starts_With "A" Case_Sensitivity.Insensitive) . should_equal ["aaa", "abab"]
Test.expect_panic_with (txtvec.filter (..Starts_With 42)) Unsupported_Argument_Types
txtvec.filter (..Ends_With "a") . should_equal ["aaa", "baaa"]
txtvec.filter (..Ends_With "a" action=Filter_Action.Remove) . should_equal ["bbb", "abab", "cccc", "ś"]
txtvec.filter (..Ends_With "A" Case_Sensitivity.Sensitive) . should_equal []
txtvec.filter (..Ends_With "A" Case_Sensitivity.Insensitive) . should_equal ["aaa", "baaa"]
Test.expect_panic_with (txtvec.filter (..Ends_With 42)) Unsupported_Argument_Types
txtvec.filter (Filter_Condition.Less than="a") . should_equal []
txtvec.filter (Filter_Condition.Greater than="b") . should_equal ["bbb", "cccc", "baaa", "ś"]
txtvec.filter (Filter_Condition.Between "b" "c") . should_equal ["bbb", "baaa"]
txtvec.filter (Filter_Condition.Is_In [1, 2]) . should_equal []
txtvec.filter (Filter_Condition.Is_In ["bbb", 's\u0301', "bbb", "FOOBAR"]) . should_equal ["bbb", "ś"]
txtvec.filter (..Less than="a") . should_equal []
txtvec.filter (..Greater than="b") . should_equal ["bbb", "cccc", "baaa", "ś"]
txtvec.filter (..Between "b" "c") . should_equal ["bbb", "baaa"]
txtvec.filter (..Is_In [1, 2]) . should_equal []
txtvec.filter (..Is_In ["bbb", 's\u0301', "bbb", "FOOBAR"]) . should_equal ["bbb", "ś"]
## Boolean based filters should fail with type error
Test.expect_panic Type_Error (txtvec.filter Filter_Condition.Is_True)
Test.expect_panic Type_Error (txtvec.filter Filter_Condition.Is_False)
Test.expect_panic Type_Error (txtvec.filter ..Is_True)
Test.expect_panic Type_Error (txtvec.filter ..Is_False)
alter ["", Nothing, " ", "a"] . filter (Filter_Condition.Is_Empty) . should_equal ["", Nothing]
alter ["", Nothing, " ", "a"] . filter (Filter_Condition.Not_Empty) . should_equal [" ", "a"]
alter ["abab", "aaabaaaa", "ba"] . filter (Filter_Condition.Like "ba") . should_equal ["ba"]
alter ["abab", "aaabaaaa"] . filter (Filter_Condition.Like "_ba_") . should_equal ["abab"]
alter ["abab", "aaabaaaa"] . filter (Filter_Condition.Like "%ba__%") . should_equal ["aaabaaaa"]
alter ["aaaa", "bbbbb", "[ab]aaaa"] . filter (Filter_Condition.Like "[ab]%") . should_equal ["[ab]aaaa"]
alter ["f.txt", "abc.*"] . filter (Filter_Condition.Like "%.*") . should_equal ["abc.*"]
alter ["", Nothing, " ", "a"] . filter (..Is_Empty) . should_equal ["", Nothing]
alter ["", Nothing, " ", "a"] . filter (..Not_Empty) . should_equal [" ", "a"]
alter ["abab", "aaabaaaa", "ba"] . filter (..Like "ba") . should_equal ["ba"]
alter ["abab", "aaabaaaa"] . filter (..Like "_ba_") . should_equal ["abab"]
alter ["abab", "aaabaaaa"] . filter (..Like "%ba__%") . should_equal ["aaabaaaa"]
alter ["aaaa", "bbbbb", "[ab]aaaa"] . filter (..Like "[ab]%") . should_equal ["[ab]aaaa"]
alter ["f.txt", "abc.*"] . filter (..Like "%.*") . should_equal ["abc.*"]
txt2 = alter ['a\n\n\n', 'a\n', 'a\n\n\nb', 'a\nb', 'caa\nbb']
txt2.filter (Filter_Condition.Like 'a_') . should_equal ['a\n']
txt2.filter (Filter_Condition.Like 'a_' Filter_Action.Remove) . should_equal ['a\n\n\n', 'a\n\n\nb', 'a\nb', 'caa\nbb']
txt2.filter (Filter_Condition.Like 'a%') . should_equal ['a\n\n\n', 'a\n', 'a\n\n\nb', 'a\nb']
txt2.filter (Filter_Condition.Like 'a_b') . should_equal ['a\nb']
txt2.filter (Filter_Condition.Like '%\nb') . should_equal ['a\n\n\nb', 'a\nb']
txt2.filter (..Like 'a_') . should_equal ['a\n']
txt2.filter (..Like 'a_' Filter_Action.Remove) . should_equal ['a\n\n\n', 'a\n\n\nb', 'a\nb', 'caa\nbb']
txt2.filter (..Like 'a%') . should_equal ['a\n\n\n', 'a\n', 'a\n\n\nb', 'a\nb']
txt2.filter (..Like 'a_b') . should_equal ['a\nb']
txt2.filter (..Like '%\nb') . should_equal ['a\n\n\nb', 'a\nb']
## NUmber based filters should fail with type error
Test.expect_panic Type_Error (txtvec.filter Filter_Condition.Is_Nan)
Test.expect_panic Type_Error (txtvec.filter Filter_Condition.Is_Infinite)
Test.expect_panic Type_Error (txtvec.filter Filter_Condition.Is_Finite)
Test.expect_panic Type_Error (txtvec.filter ..Is_Nan)
Test.expect_panic Type_Error (txtvec.filter ..Is_Infinite)
Test.expect_panic Type_Error (txtvec.filter ..Is_Finite)
group_builder.specify "should filter unicode text elements by Filter_Condition" <|
txt3 = alter ['śnieg', 's\u0301nieg', 'X', 'połać', 'połac\u0301']
txt3.filter (Filter_Condition.Starts_With 'ś') . should_equal ['śnieg', 's\u0301nieg']
txt3.filter (Filter_Condition.Contains 'ś') . should_equal ['śnieg', 's\u0301nieg']
txt3.filter (Filter_Condition.Ends_With 'ś') . should_equal []
txt3.filter (Filter_Condition.Ends_With 'ć') . should_equal ['połać', 'połac\u0301']
txt3.filter (..Starts_With 'ś') . should_equal ['śnieg', 's\u0301nieg']
txt3.filter (..Contains 'ś') . should_equal ['śnieg', 's\u0301nieg']
txt3.filter (..Ends_With 'ś') . should_equal []
txt3.filter (..Ends_With 'ć') . should_equal ['połać', 'połac\u0301']
## There is a bug with Java Regex in Unicode normalized mode (CANON_EQ) with quoting.
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8032926
# txt3.filter (Filter_Condition.Like 'ś%') . should_equal ['śnieg', 's\u0301nieg']
# txt3.filter (..Like 'ś%') . should_equal ['śnieg', 's\u0301nieg']
# This should be replaced with the disabled test above, once the related bug is fixed.
txt3.filter (Filter_Condition.Like 'ś%') . should_equal ['śnieg']
txt3.filter (..Like 'ś%') . should_equal ['śnieg']
txt4 = alter ['a', 'A', 'ś', 'Ś', 'ffi']
txt4.filter (Filter_Condition.Equal_Ignore_Case 'a') . should_equal ['a', 'A']
txt4.filter (Filter_Condition.Equal_Ignore_Case 's\u0301') . should_equal ['ś', 'Ś']
txt4.filter (Filter_Condition.Equal_Ignore_Case 'FFI') . should_equal ['ffi']
txt4.filter (..Equal_Ignore_Case 'a') . should_equal ['a', 'A']
txt4.filter (..Equal_Ignore_Case 's\u0301') . should_equal ['ś', 'Ś']
txt4.filter (..Equal_Ignore_Case 'FFI') . should_equal ['ffi']
group_builder.specify "should filter mixed elements by Filter_Condition" <|
mixed = alter [1, Nothing, "b"]
mixed.filter Filter_Condition.Is_Nothing . should_equal [Nothing]
mixed.filter Filter_Condition.Not_Nothing . should_equal [1, "b"]
Test.expect_panic Type_Error (mixed.filter Filter_Condition.Is_Empty)
Test.expect_panic Type_Error (mixed.filter Filter_Condition.Not_Empty)
mixed.filter ..Is_Nothing . should_equal [Nothing]
mixed.filter ..Not_Nothing . should_equal [1, "b"]
Test.expect_panic Type_Error (mixed.filter ..Is_Empty)
Test.expect_panic Type_Error (mixed.filter ..Not_Empty)
(alter [2, "a"]).filter (Filter_Condition.Greater 1) . should_fail_with Incomparable_Values
(alter [2, "a"]).filter (..Greater 1) . should_fail_with Incomparable_Values
group_builder.specify "should allow Nothing when filtering by Filter_Condition" <|
(alter [1, 2, Nothing, 3]).filter (Filter_Condition.Greater 2) . should_equal [3]
(alter [1, 2, Nothing, 3]).filter (Filter_Condition.Equal_Or_Less 2) . should_equal [1, 2]
(alter ["a", 2, Nothing, 2]).filter (Filter_Condition.Equal 2) . should_equal [2, 2]
(alter ["a", 2, Nothing, "a", "a"]).filter (Filter_Condition.Equal "a") . should_equal ["a", "a", "a"]
(alter [1, 2, Nothing, 3]).filter (..Greater 2) . should_equal [3]
(alter [1, 2, Nothing, 3]).filter (..Equal_Or_Less 2) . should_equal [1, 2]
(alter ["a", 2, Nothing, 2]).filter (..Equal 2) . should_equal [2, 2]
(alter ["a", 2, Nothing, "a", "a"]).filter (..Equal "a") . should_equal ["a", "a", "a"]
(alter [1, Nothing, (1/0), (0.log 0)]).filter Filter_Condition.Is_Nan . map .to_text . should_equal ["NaN"]
(alter [1, Nothing, (1/0), (0.log 0)]).filter Filter_Condition.Is_Infinite . should_equal [Number.positive_infinity]
(alter [1, Nothing, (1/0), (0.log 0)]).filter Filter_Condition.Is_Finite . should_equal [1]
(alter [1, Nothing, (1/0), (0.log 0)]).filter ..Is_Nan . map .to_text . should_equal ["NaN"]
(alter [1, Nothing, (1/0), (0.log 0)]).filter ..Is_Infinite . should_equal [Number.positive_infinity]
(alter [1, Nothing, (1/0), (0.log 0)]).filter ..Is_Finite . should_equal [1]
boolvec = alter [True, False, Nothing, True]
boolvec.filter Filter_Condition.Is_True . should_equal [True, True]
boolvec.filter Filter_Condition.Is_False . should_equal [False]
boolvec.filter ..Is_True . should_equal [True, True]
boolvec.filter ..Is_False . should_equal [False]
txtvec = alter ["abab", "baaa", Nothing, "cccc", "BAAA"]
txtvec.filter (Filter_Condition.Equal_Ignore_Case "baaA") . should_equal ["baaa", "BAAA"]
txtvec.filter (Filter_Condition.Contains "a") . should_equal ["abab", "baaa"]
txtvec.filter (Filter_Condition.Starts_With "a") . should_equal ["abab"]
txtvec.filter (Filter_Condition.Ends_With "a") . should_equal ["baaa"]
txtvec.filter (Filter_Condition.Like "b%a") . should_equal ["baaa"]
txtvec.filter (..Equal_Ignore_Case "baaA") . should_equal ["baaa", "BAAA"]
txtvec.filter (..Contains "a") . should_equal ["abab", "baaa"]
txtvec.filter (..Starts_With "a") . should_equal ["abab"]
txtvec.filter (..Ends_With "a") . should_equal ["baaa"]
txtvec.filter (..Like "b%a") . should_equal ["baaa"]
(alter ["a", 2, Nothing, 3]).filter (Filter_Condition.Is_In [Nothing, 2]) . should_equal [2, Nothing]
(alter ["a", 2, Nothing, 3]).filter (..Is_In [Nothing, 2]) . should_equal [2, Nothing]
group_builder.specify "should have a friendly error when missing Filter_Condition arguments" <|
v = alter [0, 1, 2]
r1 = v.filter Filter_Condition.Less
r1 = v.filter ..Less
r1 . should_fail_with Missing_Argument
r1.catch.to_display_text . should_contain "Provide a value for"
v.filter (Filter_Condition.Between 10) . should_fail_with Missing_Argument
v.filter (..Between 10) . should_fail_with Missing_Argument
group_builder.specify "should filter elements with indices" <|
(alter [0, 10, 2, 2] . filter_with_index (==)) . should_equal [0, 2]
@ -376,8 +376,8 @@ type_spec suite_builder name alter = suite_builder.group name group_builder->
vec.partition (x -> x.is_nothing.not && x%2==0) . should_equal <| Pair.new [2, 4] [1, 3, 5, Nothing]
(vec . partition x-> if x == 1 then Error.throw <| My_Error.Error "foo" else True) . should_fail_with My_Error
vec.partition (Filter_Condition.Between 2 4) . should_equal <| Pair.new [2, 3, 4] [1, 5, Nothing]
vec.partition (Filter_Condition.Between 2 4 Filter_Action.Remove) . should_equal <| Pair.new [1, 5, Nothing] [2, 3, 4]
vec.partition (..Between 2 4) . should_equal <| Pair.new [2, 3, 4] [1, 5, Nothing]
vec.partition (..Between 2 4 Filter_Action.Remove) . should_equal <| Pair.new [1, 5, Nothing] [2, 3, 4]
Test.expect_panic_with matcher=Type_Error (vec.partition "invalid arg")
@ -498,11 +498,11 @@ type_spec suite_builder name alter = suite_builder.group name group_builder->
input.find (x -> x%3 == 2) start=-100 . should_fail_with Index_Out_Of_Bounds
input.find (x -> x%3 == 3) if_missing=Nothing . should_equal Nothing
input.find (Filter_Condition.Greater 5) . should_equal 6
input.find (Filter_Condition.Less 5 Filter_Action.Remove) . should_equal 5
input.find (..Greater 5) . should_equal 6
input.find (..Less 5 Filter_Action.Remove) . should_equal 5
Test.expect_panic_with matcher=Type_Error (input.find "invalid arg")
alter ["b", "A", "c"] . find (Filter_Condition.Equal_Ignore_Case "a") . should_equal "A"
alter ["b", "A", "c"] . find (..Equal_Ignore_Case "a") . should_equal "A"
group_builder.specify "should allow finding the index of a value" <|
input = alter [1, 2, 3, 4, 1, 2, 3, 1, 2, 1]
@ -517,8 +517,8 @@ type_spec suite_builder name alter = suite_builder.group name group_builder->
input.index_of 2 start=11 . catch . should_equal (Index_Out_Of_Bounds.Error 11 11)
input.index_of 2 start=-11 . should_fail_with Index_Out_Of_Bounds
input.index_of (Filter_Condition.Equal_Or_Greater 2) . should_equal 1
input.index_of (Filter_Condition.Less 3 Filter_Action.Remove) . should_equal 2
input.index_of (..Equal_Or_Greater 2) . should_equal 1
input.index_of (..Less 3 Filter_Action.Remove) . should_equal 2
input.index_of "text" . should_equal Nothing
group_builder.specify "should allow finding the last index of a value" <|
@ -532,8 +532,8 @@ type_spec suite_builder name alter = suite_builder.group name group_builder->
input.last_index_of 2 start=10 . catch . should_equal (Index_Out_Of_Bounds.Error 10 10)
input.last_index_of 2 start=-11 . should_fail_with Index_Out_Of_Bounds
input.last_index_of (Filter_Condition.Equal_Or_Greater 2) . should_equal input.length-2
input.last_index_of (Filter_Condition.Less 3 Filter_Action.Remove) . should_equal 6
input.last_index_of (..Equal_Or_Greater 2) . should_equal input.length-2
input.last_index_of (..Less 3 Filter_Action.Remove) . should_equal 6
input.last_index_of "text" . should_equal Nothing
group_builder.specify "should be convertible to a list" <|

View File

@ -16,7 +16,7 @@ add_specs suite_builder =
group_builder.specify "make_regex_text_widget" <|
w = make_regex_text_widget
j = (Widgets.get_widget_json w) . to_text
j.should_contain "Option 'Leading_Whitespace' 'Named_Pattern.Leading_Whitespace' [] ''"
j.should_contain "Option '<Leading_Whitespace>' 'Named_Pattern.Leading_Whitespace' [] ''"
group_builder.specify "make_data_cleanse_vector_selector" <|
w = make_data_cleanse_vector_selector
j = (Widgets.get_widget_json w) . to_text