mirror of
https://github.com/enso-org/enso.git
synced 2024-11-22 22:10:15 +03:00
Some little bits from Book Club week 1 (#4058)
- Add `get` to Table. - Correct `Count Nothing` examples. - Add `join` to File. - Add `File_Format.all` listing all installed formats. - Add some more ALIAS entries.
This commit is contained in:
parent
4ea1880dec
commit
48e5ed9eea
@ -3,10 +3,11 @@ import project.Data.Pair.Pair
|
||||
import project.Data.Text.Encoding.Encoding
|
||||
import project.Data.Text.Text
|
||||
import project.Data.Vector.Vector
|
||||
import project.Error.Common.Type_Error
|
||||
import project.Error.Error
|
||||
import project.Error.File_Error.File_Error
|
||||
import project.Error.Illegal_Argument.Illegal_Argument
|
||||
import project.Error.Problem_Behavior.Problem_Behavior
|
||||
import project.Meta
|
||||
import project.Network.URI.URI
|
||||
import project.Network.HTTP.Header.Header
|
||||
import project.Network.HTTP.HTTP
|
||||
@ -20,7 +21,10 @@ import project.System.File_Format.File_Format
|
||||
|
||||
from project.Data.Boolean import Boolean, True, False
|
||||
|
||||
## Read a file using the specified file format
|
||||
## ALIAS Load, Open
|
||||
Read's a file into Enso.
|
||||
Uses the specified file format to parse the file into an Enso type. If not
|
||||
specified will use the file's extension to determine the file format.
|
||||
|
||||
Arguments:
|
||||
- path: The path to the file to read.
|
||||
@ -28,6 +32,8 @@ from project.Data.Boolean import Boolean, True, False
|
||||
If `Auto_Detect` is specified; the provided file determines the specific
|
||||
type and configures it appropriately. If there is no matching type then
|
||||
a `File_Error.Unsupported_Type` error is returned.
|
||||
You can use `File_Format.all` to get a list of currently loaded
|
||||
formats.
|
||||
- on_problems: Specifies the behavior when a problem occurs during the
|
||||
function.
|
||||
By default, a warning is issued, but the operation proceeds.
|
||||
@ -54,7 +60,8 @@ read : File_Format -> Problem_Behavior -> Any ! File_Error
|
||||
read path format=Auto_Detect (on_problems=Problem_Behavior.Report_Warning) =
|
||||
File.new path . read format on_problems
|
||||
|
||||
## Open and read the file at the provided `path`.
|
||||
## ALIAS Load Text, Open Text
|
||||
Open and read the file at the provided `path`.
|
||||
|
||||
Arguments:
|
||||
- path: The path of the file to open and read the contents of. It will
|
||||
@ -146,7 +153,7 @@ fetch uri method=HTTP_Method.Get headers=[] parse=True =
|
||||
_ : Vector -> Header.new (h.at 0) (h.at 1)
|
||||
_ : Pair -> Header.new (h.at 0) (h.at 1)
|
||||
_ : Header -> h
|
||||
_ -> Error.throw (Type_Error.Error Header "Invalid header type (must be a Pair, Vector or Header).")
|
||||
_ -> Error.throw (Illegal_Argument.Error "Invalid header type - all values must be Vector, Pair or Header (got "+(Meta.get_simple_type_name h)+").")
|
||||
|
||||
request = Request.new method uri parsed_headers
|
||||
response = HTTP.new.request request
|
||||
|
@ -159,7 +159,8 @@ type File
|
||||
with_input_stream self open_options action =
|
||||
Managed_Resource.bracket (self.new_input_stream open_options) (_.close) action
|
||||
|
||||
## Read a file using the specified file format
|
||||
## ALIAS Load, Open
|
||||
Read a file using the specified file format
|
||||
|
||||
Arguments:
|
||||
- format: A `File_Format` object used to read file into memory.
|
||||
@ -192,7 +193,8 @@ type File
|
||||
read self format=Auto_Detect (on_problems=Problem_Behavior.Report_Warning) =
|
||||
format.read self on_problems
|
||||
|
||||
## Reads all bytes in this file into a byte vector.
|
||||
## ALIAS Load Bytes, Open Bytes
|
||||
Reads all bytes in this file into a byte vector.
|
||||
|
||||
> Example
|
||||
Read all of the bytes in the file.
|
||||
@ -205,7 +207,8 @@ type File
|
||||
opts = [File_Access.Read]
|
||||
self.with_input_stream opts (_.read_all_bytes)
|
||||
|
||||
## Reads the whole file into a `Text`, with specified encoding.
|
||||
## ALIAS Load Text, Open Text
|
||||
Reads the whole file into a `Text`, with specified encoding.
|
||||
|
||||
Arguments:
|
||||
- encoding: The text encoding to decode the file with. Defaults to UTF-8.
|
||||
@ -241,6 +244,31 @@ type File
|
||||
/ : (Text | File) -> File
|
||||
/ self subpath = self.resolve subpath
|
||||
|
||||
## Join two or more path segments together, normalizing the `..` and `.` subpaths.
|
||||
|
||||
Arguments:
|
||||
- subpaths: The path segment or segments to join to the path of `self`.
|
||||
|
||||
> Example
|
||||
Concatenate two file path segments.
|
||||
|
||||
import Standard.Examples
|
||||
|
||||
example_append = Examples.data_dir.join "scratch_file"
|
||||
|
||||
> Example
|
||||
Concatenate multiple file path segments and normalizes the result.
|
||||
|
||||
import Standard.Examples
|
||||
|
||||
example_append = Examples.data_dir.join ["2022", "10", "31", "scratch_file"]
|
||||
join : (Text | File | Vector) -> File
|
||||
join self subpaths = case subpaths of
|
||||
_ : Vector -> (subpaths.fold self c->p-> c / p) . normalize
|
||||
_ -> self.join [subpaths]
|
||||
|
||||
## PRIVATE
|
||||
Internal method to join two path segments together.
|
||||
resolve : (Text | File) -> File
|
||||
resolve self = @Builtin_Method "File.resolve"
|
||||
|
||||
|
@ -55,6 +55,14 @@ type Auto_Detect
|
||||
|
||||
|
||||
type File_Format
|
||||
## Gets all the currently available file formats.
|
||||
|
||||
The available file formats are ones provided by libraries which are
|
||||
imported within the current project. Importing an new library may cause
|
||||
more entries to show up on this list.
|
||||
all : Vector
|
||||
all = [Auto_Detect] + format_types
|
||||
|
||||
## PRIVATE
|
||||
Implements the `File.read` for this `File_Format`
|
||||
read : File -> Problem_Behavior -> Any
|
||||
|
@ -101,9 +101,20 @@ type Table
|
||||
at : Text | Integer -> Column ! No_Such_Column | Index_Out_Of_Bounds
|
||||
at self selector=0 = case selector of
|
||||
_ : Integer -> self.make_column (self.internal_columns.at selector)
|
||||
_ : Text ->
|
||||
internal_column = self.internal_columns.find if_missing=(Error.throw (No_Such_Column.Error selector)) (p -> p.name == selector)
|
||||
self.make_column internal_column
|
||||
_ -> self.get selector (Error.throw (No_Such_Column.Error selector))
|
||||
|
||||
## Returns the column with the given name or index.
|
||||
|
||||
Arguments:
|
||||
- selector: The name or index of the column being looked up.
|
||||
- if_missing: The value to use if the selector isn't present.
|
||||
get : Text | Integer -> Any -> Column | Any
|
||||
get self selector=0 ~if_missing=Nothing =
|
||||
internal_column = case selector of
|
||||
_ : Integer -> self.internal_columns.get selector if_missing=Nothing
|
||||
_ : Text -> self.internal_columns.find (p -> p.name == selector) if_missing=Nothing
|
||||
_ -> Error.throw (Illegal_Argument.Error "expected 'selector' to be either a Text or an Integer, but got "+(Meta.get_simple_type_name selector)+".")
|
||||
if internal_column.is_nothing then if_missing else self.make_column internal_column
|
||||
|
||||
## Returns the number of columns in the table.
|
||||
column_count : Integer
|
||||
@ -497,6 +508,7 @@ type Table
|
||||
self.updated_context new_ctx
|
||||
|
||||
## UNSTABLE
|
||||
ALIAS Add Column, Update Column
|
||||
|
||||
Sets the column value at the given name.
|
||||
|
||||
@ -893,7 +905,7 @@ type Table
|
||||
> Example
|
||||
Group by the Key column, count the rows
|
||||
|
||||
table.aggregate [Aggregate_Column.Group_By "Key", Aggregate_Column.Count Nothing]
|
||||
table.aggregate [Aggregate_Column.Group_By "Key", Aggregate_Column.Count]
|
||||
aggregate : Vector Aggregate_Column -> Problem_Behavior -> Table
|
||||
aggregate self columns (on_problems=Report_Warning) =
|
||||
validated = Aggregate_Column_Helper.prepare_aggregate_columns columns self
|
||||
|
@ -202,10 +202,34 @@ type Table
|
||||
_ : Integer ->
|
||||
java_columns = Vector.from_polyglot_array self.java_table.getColumns
|
||||
Column.Value (java_columns.at selector)
|
||||
_ : Text ->
|
||||
case self.java_table.getColumnByName selector of
|
||||
Nothing -> Error.throw (No_Such_Column.Error selector)
|
||||
c -> Column.Value c
|
||||
_ -> self.get selector (Error.throw (No_Such_Column.Error selector))
|
||||
|
||||
## Returns the column with the given name or index.
|
||||
|
||||
Arguments:
|
||||
- selector: The name or index of the column being looked up.
|
||||
- if_missing: The value to use if the selector isn't present.
|
||||
|
||||
> Example
|
||||
Get the names of all of the items from the shop inventory.
|
||||
|
||||
import Standard.Examples
|
||||
|
||||
example_at = Examples.inventory_table.get "item_name"
|
||||
|
||||
> Example
|
||||
Get the last column.
|
||||
|
||||
import Standard.Examples
|
||||
|
||||
example_at = Examples.inventory_table.get -1
|
||||
get : Text | Integer -> Any -> Column | Any
|
||||
get self selector=0 ~if_missing=Nothing =
|
||||
java_column = case selector of
|
||||
_ : Integer -> Vector.from_polyglot_array self.java_table.getColumns . get selector
|
||||
_ : Text -> self.java_table.getColumnByName selector
|
||||
_ -> Error.throw (Illegal_Argument.Error "expected 'selector' to be either a Text or an Integer, but got "+(Meta.get_simple_type_name selector)+".")
|
||||
if java_column.is_nothing then if_missing else Column.Value java_column
|
||||
|
||||
## Returns the number of columns in the table.
|
||||
column_count : Integer
|
||||
@ -502,7 +526,7 @@ type Table
|
||||
> Example
|
||||
Group by the Key column, count the rows
|
||||
|
||||
table.aggregate [Group_By "Key", Count Nothing]
|
||||
table.aggregate [Aggregate_Column.Group_By "Key", Aggregate_Column.Count]
|
||||
aggregate : Vector Aggregate_Column -> Problem_Behavior -> Table
|
||||
aggregate self columns (on_problems=Report_Warning) =
|
||||
validated = Aggregate_Column_Helper.prepare_aggregate_columns columns self
|
||||
@ -924,7 +948,7 @@ type Table
|
||||
drop self range=(First 1) =
|
||||
Index_Sub_Range_Module.drop_helper self.row_count self.rows.at self.slice (slice_ranges self) range
|
||||
|
||||
## ALIAS Add Column
|
||||
## ALIAS Add Column, Update Column
|
||||
|
||||
Sets the column value at the given name.
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
from Standard.Base import all
|
||||
import Standard.Base.Error.Common.Type_Error
|
||||
import Standard.Base.Error.Illegal_Argument.Illegal_Argument
|
||||
import Standard.Base.Error.Unimplemented.Unimplemented
|
||||
|
||||
import project.Data.Table.Table
|
||||
@ -50,7 +51,7 @@ Table.from_objects value fields=Nothing =
|
||||
_ : Number -> ["Value"]
|
||||
_ : Boolean -> ["Value"]
|
||||
_ : Text -> ["Value"]
|
||||
_ -> Error.throw (Type_Error.Error Any "Invalid item within Vector for Table.from_objects. Currently only JS_Object, Number, Boolean, Text and Nothing are supported.")
|
||||
_ -> Error.throw (Illegal_Argument.Error "Invalid item within Vector for Table.from_objects. Currently only JS_Object, Number, Boolean, Text and Nothing are supported (got "+(Meta.get_simple_type_name v)+").")
|
||||
|
||||
get_value v field = case v of
|
||||
_ : JS_Object -> v.get field
|
||||
@ -87,4 +88,4 @@ Table.from_objects value fields=Nothing =
|
||||
|
||||
Table.new (used_fields.zip used_values)
|
||||
_ : Array -> Table.from_objects (Vector.from_polyglot_array value) fields
|
||||
_ -> Error.throw (Type_Error.Error Any "Invalid value for Table.from_objects. Currently must be one of JS_Object, Vector, Array, Number, Boolean, Text and Nothing are supported.")
|
||||
_ -> Error.throw (Illegal_Argument.Error "Invalid value for Table.from_objects. Currently must be one of JS_Object, Vector, Array, Number, Boolean, Text and Nothing are supported (got "+(Meta.get_simple_type_name value)+").")
|
||||
|
@ -28,7 +28,7 @@ bench =
|
||||
IO.println <| "Making table data..."
|
||||
table = create_table vector_size
|
||||
|
||||
Bench.measure (table.aggregate [Count Nothing]) "Count table" iter_size num_iterations
|
||||
Bench.measure (table.aggregate [Count]) "Count table" iter_size num_iterations
|
||||
Bench.measure (table.aggregate [Maximum "ValueWithNothing"]) "Max table" iter_size num_iterations
|
||||
Bench.measure (table.aggregate [Sum "ValueWithNothing"]) "Sum table" iter_size num_iterations
|
||||
# Bench.measure (table.aggregate [Count_Distinct "Index"]) "Count Distinct table" iter_size num_iterations
|
||||
@ -36,7 +36,7 @@ bench =
|
||||
# Bench.measure (table.aggregate [Median "Value"]) "Median table" iter_size num_iterations
|
||||
# Bench.measure (table.aggregate [Mode "Index"]) "Mode table" iter_size num_iterations
|
||||
|
||||
Bench.measure (table.aggregate [Group_By "Index", Count Nothing]) "Count grouped" iter_size num_iterations
|
||||
Bench.measure (table.aggregate [Group_By "Index", Count]) "Count grouped" iter_size num_iterations
|
||||
Bench.measure (table.aggregate [Group_By "Index", Maximum "ValueWithNothing"]) "Max table" iter_size num_iterations
|
||||
Bench.measure (table.aggregate [Group_By "Index", Sum "ValueWithNothing"]) "Sum table" iter_size num_iterations
|
||||
# Bench.measure (table.aggregate [Group_By "Index", Count_Distinct "Code"]) "Count Distinct grouped" iter_size num_iterations
|
||||
@ -44,7 +44,7 @@ bench =
|
||||
# Bench.measure (table.aggregate [Group_By "Index", Median "Value"]) "Median grouped" iter_size num_iterations
|
||||
# Bench.measure (table.aggregate [Group_By "Index", Mode "Index"]) "Mode grouped" iter_size num_iterations
|
||||
|
||||
Bench.measure (table.aggregate [Group_By "Index", Group_By "Flag", Count Nothing]) "Count 2 level groups" iter_size num_iterations
|
||||
Bench.measure (table.aggregate [Group_By "Index", Group_By "Flag", Count]) "Count 2 level groups" iter_size num_iterations
|
||||
Bench.measure (table.aggregate [Group_By "Index", Group_By "Flag", Maximum "ValueWithNothing"]) "Max table" iter_size num_iterations
|
||||
Bench.measure (table.aggregate [Group_By "Index", Group_By "Flag", Sum "ValueWithNothing"]) "Sum table" iter_size num_iterations
|
||||
# Bench.measure (table.aggregate [Group_By "Index", Group_By "Flag", Count_Distinct "Code"]) "Count Distinct 2 level groups" iter_size num_iterations
|
||||
|
@ -41,7 +41,7 @@ spec setup =
|
||||
|
||||
Test.group prefix+"Table.aggregate should summarize whole table" <|
|
||||
Test.specify "should be able to count" <|
|
||||
grouped = table.aggregate [Count Nothing]
|
||||
grouped = table.aggregate [Count]
|
||||
materialized = materialize grouped
|
||||
grouped.row_count . should_equal 1
|
||||
materialized.column_count . should_equal 1
|
||||
@ -194,7 +194,7 @@ spec setup =
|
||||
|
||||
Test.group prefix+"Table.aggregate should summarize empty table" <|
|
||||
Test.specify "should be able to count" <|
|
||||
grouped = empty_table.aggregate [Count Nothing]
|
||||
grouped = empty_table.aggregate [Count]
|
||||
materialized = materialize grouped
|
||||
grouped.row_count . should_equal 1
|
||||
materialized.column_count . should_equal 1
|
||||
@ -307,7 +307,7 @@ spec setup =
|
||||
|
||||
Test.group prefix+"Table.aggregate should not summarize empty table when grouped" <|
|
||||
Test.specify "should be able to count" <|
|
||||
grouped = empty_table.aggregate [Group_By 0, Count Nothing]
|
||||
grouped = empty_table.aggregate [Group_By 0, Count]
|
||||
materialized = materialize grouped
|
||||
grouped.row_count . should_equal 0
|
||||
materialized.column_count . should_equal 2
|
||||
@ -407,7 +407,7 @@ spec setup =
|
||||
|
||||
Test.group prefix+"Table.aggregate should be able to group on single field" <|
|
||||
Test.specify "should be able to count" <|
|
||||
grouped = table.aggregate [Group_By "Index", Count Nothing]
|
||||
grouped = table.aggregate [Group_By "Index", Count]
|
||||
materialized = materialize grouped
|
||||
grouped.row_count . should_equal 10
|
||||
materialized.column_count . should_equal 2
|
||||
@ -597,7 +597,7 @@ spec setup =
|
||||
|
||||
Test.group prefix+"Table.aggregate should be able to group on multiple fields not in left columns" <|
|
||||
Test.specify "should be able to count" <|
|
||||
grouped = table.aggregate [Group_By "Flag", Count Nothing, Group_By "Index"]
|
||||
grouped = table.aggregate [Group_By "Flag", Count, Group_By "Index"]
|
||||
materialized = materialize grouped
|
||||
grouped.row_count . should_equal 20
|
||||
materialized.column_count . should_equal 3
|
||||
@ -1331,7 +1331,7 @@ spec setup =
|
||||
problems.at 0 . rows . length . should_equal 15
|
||||
|
||||
Test.specify "should merge Floating Point Grouping warnings" <|
|
||||
new_table = table.aggregate [Group_By "Float", Count Nothing]
|
||||
new_table = table.aggregate [Group_By "Float", Count]
|
||||
problems = Warning.get_all new_table . map .value
|
||||
problems.length . should_equal 1
|
||||
problems.at 0 . is_a Floating_Point_Grouping.Error . should_be_true
|
||||
|
@ -1,5 +1,6 @@
|
||||
from Standard.Base import all
|
||||
import Standard.Base.Error.Common.Index_Out_Of_Bounds
|
||||
import Standard.Base.Error.Illegal_Argument.Illegal_Argument
|
||||
|
||||
from Standard.Table.Errors import all
|
||||
|
||||
@ -30,6 +31,7 @@ spec setup =
|
||||
column_1.to_vector . should_equal [4, 5, 6]
|
||||
|
||||
table.at "nonexistent column name" . should_fail_with No_Such_Column.Error
|
||||
|
||||
Test.specify "should allow selecting columns by index" <|
|
||||
column_1 = table.at
|
||||
column_1.name . should_equal "foo"
|
||||
@ -45,6 +47,39 @@ spec setup =
|
||||
|
||||
table.at 100 . should_fail_with Index_Out_Of_Bounds.Error
|
||||
|
||||
Test.specify "should fail with Type Error is not an Integer or Text" <|
|
||||
table.at (Pair.new 1 2) . should_fail_with Illegal_Argument.Error
|
||||
table.at (Pair.new 1 2) . catch . to_display_text . should_equal "Illegal Argument: expected 'selector' to be either a Text or an Integer, but got Pair.Value."
|
||||
|
||||
Test.group prefix+"Table.get" <|
|
||||
Test.specify "should allow selecting columns by name" <|
|
||||
column_1 = table.get "bar"
|
||||
column_1.name . should_equal "bar"
|
||||
column_1.to_vector . should_equal [4, 5, 6]
|
||||
|
||||
table.get "nonexistent column name" . should_equal Nothing
|
||||
table.get "nonexistent column name" column_1 . name . should_equal "bar"
|
||||
|
||||
Test.specify "should allow selecting columns by index" <|
|
||||
column_1 = table.get
|
||||
column_1.name . should_equal "foo"
|
||||
column_1.to_vector . should_equal [1, 2, 3]
|
||||
|
||||
column_2 = table.get 2
|
||||
column_2.name . should_equal "Baz"
|
||||
column_2.to_vector . should_equal [7, 8, 9]
|
||||
|
||||
column_3 = table.get -1
|
||||
column_3.name . should_equal "abcd123"
|
||||
column_3.to_vector . should_equal [19, 20, 21]
|
||||
|
||||
table.get 100 . should_equal Nothing
|
||||
table.get 100 column_1 . name . should_equal "foo"
|
||||
|
||||
Test.specify "should fail with Type Error is not an Integer or Text" <|
|
||||
table.get (Pair.new 1 2) . should_fail_with Illegal_Argument.Error
|
||||
table.get (Pair.new 1 2) . catch . to_display_text . should_equal "Illegal Argument: expected 'selector' to be either a Text or an Integer, but got Pair.Value."
|
||||
|
||||
Test.group prefix+"Table.column_names" <|
|
||||
Test.specify "should return the names of all columns" <|
|
||||
table.column_names . should_equal ["foo", "bar", "Baz", "foo_1", "foo_2", "ab.+123", "abcd123"]
|
||||
|
@ -39,7 +39,7 @@ spec = Test.group "Aggregate Columns" <|
|
||||
result.should_equal expected_result
|
||||
|
||||
Test.specify "should be able to count a set" <|
|
||||
test_aggregator simple_table (Count Nothing) "Count" simple_table.row_count
|
||||
test_aggregator simple_table (Count) "Count" simple_table.row_count
|
||||
test_aggregator simple_table (Count test_name) test_name simple_table.row_count
|
||||
test_aggregator empty_table (Count test_name) test_name empty_table.row_count
|
||||
|
||||
|
@ -21,6 +21,15 @@ spec =
|
||||
file = File.new sample_file
|
||||
file . should_equal sample_file
|
||||
|
||||
Test.specify "should allow joining sections" <|
|
||||
f_1 = File.new "foo/bar"
|
||||
(File.new "foo" / "bar") . normalize . should_equal f_1
|
||||
File.new "foo" . join "bar" . should_equal f_1
|
||||
|
||||
f_2 = File.new "foo/a/b/c/d/e"
|
||||
File.new "foo" . join "a" . join "b" . join "c" . join "d" . join "e" . should_equal f_2
|
||||
File.new "foo" . join ["a", "b", "c", "d", "e"] . should_equal f_2
|
||||
|
||||
Test.specify "should check if file exists" <|
|
||||
non_existent_file.exists.should_be_false
|
||||
sample_file.exists.should_be_true
|
||||
@ -41,8 +50,9 @@ spec =
|
||||
|
||||
Test.specify "should normalize file" <|
|
||||
f_1 = File.new "foo"
|
||||
f_2 = File.new "bar/../baz/../foo"
|
||||
f_2.normalize.should_equal f_1
|
||||
File.new "bar/../baz/../foo" . normalize . should_equal f_1
|
||||
(File.new "bar" / ".." / "baz" / ".." / "foo") . normalize . should_equal f_1
|
||||
File.new "bar" . join ["..", "baz", "..", "foo"] . should_equal f_1
|
||||
|
||||
Test.specify "should handle `==` on files" <|
|
||||
(File.new "foo").should_equal (File.new "foo")
|
||||
|
Loading…
Reference in New Issue
Block a user