mirror of
https://github.com/enso-org/enso.git
synced 2024-12-23 13:02:07 +03:00
Table Visualization and display text changes. (#6382)
- Missing tests from number parsing. - Fix type signature on some warning methods. - Fix warnings on `Standard.Database.Data.Table.parse_values`. - Added test for `Nothing` and empty string on `use_first_row_as_names`. - New API for `Number.format` taking a simple format string and `Locale`. - Add ellipsis to truncated `Text.to_display_text`. - Adjusted built-in `to_display_text` for numbers to not include type (but also to display BigInteger as value). - Remove `Noise.Generator` interface type. - Json: Added `to_display_text` to `JS_Object`. - Time: Added `to_display_text` for `Date`, `Time_Of_Day`, `Date_Time`, `Duration` and `Period`. - Text: Added `to_display_text` to `Locale`, `Case_Sensitivity`, `Encoding`, `Text_Sub_Range`, `Span`, `Utf_16_Span`. - System: Added `to_display_text` to `File`, `File_Permissions`, `Process_Result` and `Exit_Code`. - Network: Added `to_display_text` to `URI`, `HTTP_Status_Code` and `Header`. - Added `to_display_text` to `Maybe`, `Regression`, `Pair`, `Range`, `Filter_Condition`. - Added support for `to_js_object` and `to_display_text` to `Random_Number_Generator`. - Verified all error types have `to_display_text`. - Removed `BigInt`, `Date`, `Date_Time` and `Time_Of_Day` JS based rendering as using `to_display_text` now. - Added support for rendering nested structures in the table viz.
This commit is contained in:
parent
0e5ee35aba
commit
0e51131809
8
.github/CODEOWNERS
vendored
8
.github/CODEOWNERS
vendored
@ -29,16 +29,16 @@ Cargo.toml
|
||||
# Engine (old)
|
||||
# This section should be removed once the engine moves to /app/engine
|
||||
/build.sbt @4e6 @jaroslavtulach @hubertp
|
||||
/distribution/ @4e6 @jdunkerley @radeusgd
|
||||
/distribution/ @4e6 @jdunkerley @radeusgd @GregoryTravis
|
||||
/engine/ @4e6 @jaroslavtulach @hubertp
|
||||
/project/ @4e6 @jaroslavtulach @hubertp
|
||||
/test/ @jdunkerley @radeusgd
|
||||
/test/ @jdunkerley @radeusgd @GregoryTravis
|
||||
/tools/ @4e6 @jaroslavtulach @radeusgd
|
||||
|
||||
# Enso Libraries
|
||||
# This section should be amended once the engine moves to /app/engine
|
||||
/distribution/lib/ @jdunkerley @radeusgd
|
||||
/std-bits/ @jdunkerley @radeusgd
|
||||
/distribution/lib/ @jdunkerley @radeusgd @GregoryTravis
|
||||
/std-bits/ @jdunkerley @radeusgd @GregoryTravis
|
||||
|
||||
# Cloud Dashboard & Authentication
|
||||
/app/ide-desktop/lib/dashboard @PabloBuchu @indiv0 @somebody1234
|
||||
|
@ -32,6 +32,10 @@ class TableVisualization extends Visualization {
|
||||
}
|
||||
|
||||
onDataReceived(data) {
|
||||
function addRowIndex(data) {
|
||||
return data.map((row, i) => ({ ['#']: i, ...row }))
|
||||
}
|
||||
|
||||
function hasExactlyKeys(keys, obj) {
|
||||
return Object.keys(obj).length === keys.length && keys.every(k => obj.hasOwnProperty(k))
|
||||
}
|
||||
@ -65,44 +69,8 @@ class TableVisualization extends Visualization {
|
||||
|
||||
if (content instanceof Object) {
|
||||
const type = content.type
|
||||
if (type === 'BigInt') {
|
||||
return BigInt(content.value)
|
||||
} else if (content['_display_text_']) {
|
||||
if (content['_display_text_']) {
|
||||
return content['_display_text_']
|
||||
} else if (type === 'Date') {
|
||||
return new Date(content.year, content.month - 1, content.day)
|
||||
.toISOString()
|
||||
.substring(0, 10)
|
||||
} else if (type === 'Time_Of_Day') {
|
||||
const js_date = new Date(
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
content.hour,
|
||||
content.minute,
|
||||
content.second,
|
||||
content.nanosecond / 1000000
|
||||
)
|
||||
return (
|
||||
js_date.toTimeString().substring(0, 8) +
|
||||
(js_date.getMilliseconds() === 0 ? '' : '.' + js_date.getMilliseconds())
|
||||
)
|
||||
} else if (type === 'Date_Time') {
|
||||
const js_date = new Date(
|
||||
content.year,
|
||||
content.month - 1,
|
||||
content.day,
|
||||
content.hour,
|
||||
content.minute,
|
||||
content.second,
|
||||
content.nanosecond / 1000000
|
||||
)
|
||||
return (
|
||||
js_date.toISOString().substring(0, 10) +
|
||||
' ' +
|
||||
js_date.toTimeString().substring(0, 8) +
|
||||
(js_date.getMilliseconds() === 0 ? '' : '.' + js_date.getMilliseconds())
|
||||
)
|
||||
} else {
|
||||
return `{ ${type} Object }`
|
||||
}
|
||||
@ -136,7 +104,7 @@ class TableVisualization extends Visualization {
|
||||
sortable: true,
|
||||
filter: true,
|
||||
resizable: true,
|
||||
minWidth: 50,
|
||||
minWidth: 25,
|
||||
headerValueGetter: params => params.colDef.field,
|
||||
},
|
||||
onColumnResized: e => this.lockColumnSize(e),
|
||||
@ -158,22 +126,49 @@ class TableVisualization extends Visualization {
|
||||
},
|
||||
])
|
||||
this.agGridOptions.api.setRowData([{ Error: parsedData.error }])
|
||||
} else if (parsedData.json != null && isMatrix(parsedData.json)) {
|
||||
columnDefs = parsedData.json[0].map((_, i) => ({ field: i.toString() }))
|
||||
rowData = parsedData.json
|
||||
} else if (parsedData.type === 'Matrix') {
|
||||
let defs = [{ field: '#' }]
|
||||
for (let i = 0; i < parsedData.column_count; i++) {
|
||||
defs.push({ field: i.toString() })
|
||||
}
|
||||
columnDefs = defs
|
||||
rowData = addRowIndex(parsedData.json)
|
||||
dataTruncated = parsedData.all_rows_count !== parsedData.json.length
|
||||
} else if (parsedData.json != null && isObjectMatrix(parsedData.json)) {
|
||||
let firstKeys = Object.keys(parsedData.json[0])
|
||||
} else if (parsedData.type === 'Object_Matrix') {
|
||||
let defs = [{ field: '#' }]
|
||||
let keys = {}
|
||||
parsedData.json.forEach(val => {
|
||||
if (val) {
|
||||
Object.keys(val).forEach(k => {
|
||||
if (!keys[k]) {
|
||||
keys[k] = true
|
||||
defs.push({ field: k })
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
columnDefs = defs
|
||||
rowData = addRowIndex(parsedData.json)
|
||||
dataTruncated = parsedData.all_rows_count !== parsedData.json.length
|
||||
} else if (isMatrix(parsedData.json)) {
|
||||
// Kept to allow visualization from older versions of the backend.
|
||||
columnDefs = [
|
||||
{ field: '#' },
|
||||
...parsedData.json[0].map((_, i) => ({ field: i.toString() })),
|
||||
]
|
||||
rowData = addRowIndex(parsedData.json)
|
||||
dataTruncated = parsedData.all_rows_count !== parsedData.json.length
|
||||
} else if (isObjectMatrix(parsedData.json)) {
|
||||
// Kept to allow visualization from older versions of the backend.
|
||||
let firstKeys = [{ field: '#' }, ...Object.keys(parsedData.json[0])]
|
||||
columnDefs = firstKeys.map(field => ({ field }))
|
||||
rowData = parsedData.json.map(obj =>
|
||||
firstKeys.reduce((acc, key) => ({ ...acc, [key]: toRender(obj[key]) }), {})
|
||||
)
|
||||
rowData = addRowIndex(parsedData.json)
|
||||
dataTruncated = parsedData.all_rows_count !== parsedData.json.length
|
||||
} else if (parsedData.json != null && Array.isArray(parsedData.json)) {
|
||||
} else if (Array.isArray(parsedData.json)) {
|
||||
columnDefs = [{ field: '#' }, { field: 'Value' }]
|
||||
rowData = parsedData.json.map((row, i) => ({ ['#']: i, Value: toRender(row) }))
|
||||
dataTruncated = parsedData.all_rows_count !== parsedData.json.length
|
||||
} else if (parsedData.json != null) {
|
||||
} else if (parsedData.json !== undefined) {
|
||||
columnDefs = [{ field: 'Value' }]
|
||||
rowData = [{ Value: toRender(parsedData.json) }]
|
||||
} else {
|
||||
|
@ -199,6 +199,37 @@ type Filter_Condition
|
||||
Is_In values -> values.contains
|
||||
Not_In values -> elem -> values.contains elem . not
|
||||
|
||||
## PRIVATE
|
||||
Convert to a display representation of this Filter_Condition.
|
||||
to_display_text : Text
|
||||
to_display_text self =
|
||||
render_case case_sensitivity =
|
||||
if case_sensitivity == Case_Sensitivity.Default then "" else " Case " + case_sensitivity.to_display_text
|
||||
|
||||
condition = case self of
|
||||
Less value -> "<" + value.to_display_text
|
||||
Equal_Or_Less value -> "<=" + value.to_display_text
|
||||
Equal value -> "==" + value.to_display_text
|
||||
Equal_Or_Greater value -> ">=" + value.to_display_text
|
||||
Greater value -> ">" + value.to_display_text
|
||||
Not_Equal value -> "!=" + value.to_display_text
|
||||
Between lower upper -> "Between " + lower.to_display_text + " And " + upper.to_display_text
|
||||
Starts_With prefix case_sensitivity -> "Starts With " + prefix.to_display_text + (render_case case_sensitivity)
|
||||
Ends_With suffix case_sensitivity -> "Ends With " + suffix.to_display_text + (render_case case_sensitivity)
|
||||
Contains substring case_sensitivity -> "Contains " + substring.to_display_text + (render_case case_sensitivity)
|
||||
Not_Contains substring case_sensitivity -> "Not Contains " + substring.to_display_text + (render_case case_sensitivity)
|
||||
Is_Nothing -> "is Nothing"
|
||||
Not_Nothing -> "is Not Nothing"
|
||||
Is_True -> "is True"
|
||||
Is_False -> "is False"
|
||||
Is_Empty -> "is Empty"
|
||||
Not_Empty -> "is Not Empty"
|
||||
Like sql_pattern -> "Like " + sql_pattern.to_display_text
|
||||
Not_Like sql_pattern -> "Not Like " + sql_pattern.to_display_text
|
||||
Is_In values -> "is in " + values.to_display_text
|
||||
Not_In values -> "is not in " + values.to_display_text
|
||||
"Filter Condition: " + condition
|
||||
|
||||
## PRIVATE
|
||||
Gets a widget set up for a Filter_Condition.
|
||||
default_widget =
|
||||
|
@ -2,6 +2,7 @@ import project.Any.Any
|
||||
import project.Data.Numbers.Integer
|
||||
import project.Data.Range.Range
|
||||
import project.Data.Range.Extensions
|
||||
import project.Data.Text.Text
|
||||
import project.Data.Vector.Vector
|
||||
import project.Errors.Common.Index_Out_Of_Bounds
|
||||
import project.Error.Error
|
||||
@ -55,6 +56,17 @@ type Index_Sub_Range
|
||||
input, an error is raised.
|
||||
Every (step:Integer) (first:Integer=0)
|
||||
|
||||
## PRIVATE
|
||||
Convert to a display representation of this Index_Sub_Range.
|
||||
to_display_text : Text
|
||||
to_display_text self = case self of
|
||||
Index_Sub_Range.First count -> "First " + count.to_display_text
|
||||
Index_Sub_Range.Last count -> "Last " + count.to_display_text
|
||||
Index_Sub_Range.While f -> "While " + f.to_display_text
|
||||
Index_Sub_Range.By_Index indexes -> "By_Index " + indexes.to_display_text
|
||||
Index_Sub_Range.Sample count _ -> "Sample " + count.to_display_text
|
||||
Index_Sub_Range.Every step first -> "Every " + step.to_display_text + (if first == 0 then "" else " from " + first.to_display_text)
|
||||
|
||||
## PRIVATE
|
||||
Resolves a vector of ranges or indices into a vector of ranges that fit
|
||||
within a sequence.
|
||||
|
@ -1,4 +1,5 @@
|
||||
import project.Data.Numbers.Number
|
||||
import project.Data.Text.Text
|
||||
|
||||
from project.Data.Boolean import Boolean, False
|
||||
|
||||
@ -136,3 +137,15 @@ type Interval
|
||||
example_not_empty = Interval.inclusive 0 0.001 . not_empty
|
||||
not_empty : Boolean
|
||||
not_empty self = self.is_empty.not
|
||||
|
||||
## PRIVATE
|
||||
Convert to a display representation of this Interval.
|
||||
to_display_text : Text
|
||||
to_display_text self =
|
||||
prefix = case self.start of
|
||||
Bound.Exclusive s -> "(" + s.to_display_text + ", "
|
||||
Bound.Inclusive s -> "[" + s.to_display_text + ", "
|
||||
suffix = case self.end of
|
||||
Bound.Exclusive e -> e.to_display_text + ")"
|
||||
Bound.Inclusive e -> e.to_display_text + "]"
|
||||
prefix + suffix
|
||||
|
@ -180,6 +180,12 @@ type JS_Object
|
||||
to_text : Text
|
||||
to_text self = Json.stringify self
|
||||
|
||||
## PRIVATE
|
||||
Convert JS_Object to a friendly string.
|
||||
to_display_text : Text
|
||||
to_display_text self =
|
||||
self.to_text.to_display_text
|
||||
|
||||
## Convert to a JSON representation.
|
||||
to_json : Text
|
||||
to_json self = self.to_text
|
||||
|
@ -413,4 +413,11 @@ type Locale
|
||||
## PRIVATE
|
||||
Converts the locale to text.
|
||||
to_text : Text | Nothing
|
||||
to_text self = self.java_locale.toLanguageTag
|
||||
to_text self =
|
||||
tag = self.java_locale.toLanguageTag
|
||||
if tag == "" then "Default" else tag
|
||||
|
||||
## PRIVATE
|
||||
Convert Locale to a friendly string.
|
||||
to_display_text : Text
|
||||
to_display_text self = "Locale(" + self.to_text + ")"
|
||||
|
@ -1,4 +1,5 @@
|
||||
import project.Any.Any
|
||||
import project.Data.Text.Text
|
||||
|
||||
from project.Data.Boolean import Boolean, True, False
|
||||
|
||||
@ -54,5 +55,13 @@ type Maybe
|
||||
Maybe.None -> False
|
||||
Maybe.Some _ -> True
|
||||
|
||||
## Check if the maybe value is `None`.
|
||||
is_none : Boolean
|
||||
is_none self = self.is_some.not
|
||||
|
||||
## PRIVATE
|
||||
Convert Maybe to a friendly string.
|
||||
to_display_text : Text
|
||||
to_display_text self = case self of
|
||||
Maybe.None -> "None"
|
||||
Maybe.Some val -> "Some(" + val.to_display_text + ")"
|
||||
|
@ -7,28 +7,7 @@ import project.Errors.Unimplemented.Unimplemented
|
||||
polyglot java import java.lang.Long
|
||||
polyglot java import java.util.Random
|
||||
|
||||
## PRIVATE
|
||||
|
||||
The interface for the noise generator abstraction.
|
||||
|
||||
To be a valid generator, it must provide the `step` method as described
|
||||
below.
|
||||
type Generator
|
||||
## PRIVATE
|
||||
|
||||
Step the generator to produce the next value..
|
||||
|
||||
Arguments:
|
||||
- The input number, which is intended for use as a seed.
|
||||
- A range for output values, which should range over the chosen output
|
||||
type.
|
||||
|
||||
The return type may be chosen freely by the generator implementation, as
|
||||
it usually depends on the generator and its intended use.
|
||||
step : Number -> Interval -> Any
|
||||
step self _ _ = Unimplemented.throw "Only intended to demonstrate an interface."
|
||||
|
||||
## A noise generator that implements a seeded deterministic random peterbation
|
||||
## A noise generator that implements a seeded deterministic random perturbation
|
||||
of the input.
|
||||
|
||||
It produces what is commonly termed "white" noise, where any value in the
|
||||
@ -73,6 +52,6 @@ type Deterministic_Random
|
||||
> Example
|
||||
Deterministically perturb the input number 1.
|
||||
1.noise
|
||||
Number.noise : Interval -> Generator -> Any
|
||||
Number.noise : Interval -> Deterministic_Random -> Any
|
||||
Number.noise self (interval = Interval.exclusive 0 1) gen=Deterministic_Random =
|
||||
gen.step self interval
|
||||
|
@ -10,9 +10,10 @@ from project.Data.Boolean import Boolean, True, False
|
||||
|
||||
polyglot java import java.lang.Double
|
||||
polyglot java import java.lang.Math
|
||||
polyglot java import java.lang.String
|
||||
polyglot java import java.lang.Long
|
||||
polyglot java import java.lang.NumberFormatException
|
||||
polyglot java import java.text.DecimalFormat
|
||||
polyglot java import java.text.DecimalFormatSymbols
|
||||
polyglot java import java.text.NumberFormat
|
||||
polyglot java import java.text.ParseException
|
||||
|
||||
@ -263,20 +264,21 @@ type Number
|
||||
log : Number -> Decimal
|
||||
log self base = self.ln / base.ln
|
||||
|
||||
## UNSTABLE This API is not user-friendly and will be improved in the future.
|
||||
|
||||
Converts a numeric value to a string, using the Java string formatting
|
||||
syntax.
|
||||
## Converts a numeric value to a string, using the Java DecimalFormat
|
||||
formatter.
|
||||
|
||||
Arguments:
|
||||
- fmt: The java-style formatting specifier.
|
||||
- format: The java-style formatting specifier.
|
||||
|
||||
> Example
|
||||
Convert the value 5 to a string.
|
||||
Convert the value 5000 to a string.
|
||||
|
||||
5.format "%x"
|
||||
format : Text -> Text
|
||||
format self fmt = String.format fmt self
|
||||
5000.format "#,##0"
|
||||
format : Text -> Locale -> Text
|
||||
format self format locale=Locale.default =
|
||||
symbols = DecimalFormatSymbols.new locale.java_locale
|
||||
formatter = DecimalFormat.new format symbols
|
||||
formatter.format self
|
||||
|
||||
## Checks equality of numbers, using an `epsilon` value.
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
import project.Any.Any
|
||||
import project.Data.Boolean.Boolean
|
||||
import project.Data.Numbers.Integer
|
||||
import project.Data.Text.Text
|
||||
import project.Data.Text.Extensions
|
||||
import project.Data.Vector.Vector
|
||||
import project.Errors.Common.Index_Out_Of_Bounds
|
||||
import project.Errors.Common.Not_Found
|
||||
@ -248,6 +250,17 @@ type Pair
|
||||
f self.second
|
||||
Nothing
|
||||
|
||||
## PRIVATE
|
||||
Convert to a display representation of this Pair.
|
||||
to_display_text : Text
|
||||
to_display_text self =
|
||||
first = self.first.to_display_text
|
||||
second = self.second.to_display_text
|
||||
if first.length + second.length < 73 then "Pair(" + first + ", " + second + ")" else
|
||||
first_trim = if first.length > 36 then first.take 34 + " …" else first
|
||||
second_trim = if second.length > 36 then second.take 34 + " …" else second
|
||||
"Pair(" + first_trim + ", " + second_trim + ")"
|
||||
|
||||
## PRIVATE
|
||||
check_start_valid start function max=3 =
|
||||
used_start = if start < 0 then start + 2 else start
|
||||
|
@ -430,6 +430,14 @@ type Range
|
||||
@Tail_Call fold_function (function current value) (value + self.step)
|
||||
fold_function self.start self.start+self.step
|
||||
|
||||
## PRIVATE
|
||||
Convert to a display representation of this Range.
|
||||
to_display_text : Text
|
||||
to_display_text self =
|
||||
start = "[" + self.start.to_display_text + " .. " + self.end.to_display_text
|
||||
step = if self.step.abs == 1 then "" else " by " + self.step.to_display_text
|
||||
start + step + "]"
|
||||
|
||||
## PRIVATE
|
||||
throw_zero_step_error = Error.throw (Illegal_State.Error "A range with step = 0 is ill-formed.")
|
||||
|
||||
|
@ -24,6 +24,17 @@ type Model
|
||||
## Fit a power series (y = A x ^ B) to the data.
|
||||
Power
|
||||
|
||||
## PRIVATE
|
||||
Convert to a display representation of this Model.
|
||||
to_display_text : Text
|
||||
to_display_text self = case self of
|
||||
Model.Linear intercept ->
|
||||
if intercept.is_nothing then "Linear" else "Linear(intercept: " + intercept.to_display_text + ")"
|
||||
Model.Exponential intercept ->
|
||||
if intercept.is_nothing then "Exponential" else "Exponential(intercept: " + intercept.to_display_text + ")"
|
||||
Model.Logarithmic -> "Logarithmic"
|
||||
Model.Power -> "Power"
|
||||
|
||||
## PRIVATE
|
||||
Computes the R Squared value for a model and returns a new instance.
|
||||
fitted_model_with_r_squared : Any -> Number -> Number -> Vector -> Vector -> Fitted_Model
|
||||
@ -33,7 +44,6 @@ type Model
|
||||
constructor a b r_squared
|
||||
|
||||
## PRIVATE
|
||||
|
||||
Computes the natural log series as long as all values are positive.
|
||||
ln_series : Vector -> Text -> Vector ! Illegal_Argument
|
||||
ln_series xs series_name="Values" =
|
||||
@ -82,12 +92,16 @@ type Fitted_Model
|
||||
Display the fitted line.
|
||||
to_text : Text
|
||||
to_text self =
|
||||
equation = case self of
|
||||
Fitted_Model.Linear slope intercept _ -> slope.to_text + " * X + " + intercept.to_text
|
||||
Fitted_Model.Exponential a b _ -> a.to_text + " * (" + b.to_text + " * X).exp"
|
||||
Fitted_Model.Logarithmic a b _ -> a.to_text + " * X.ln + " + b.to_text
|
||||
Fitted_Model.Power a b _ -> a.to_text + " * X ^ " + b.to_text
|
||||
"Fitted_Model(" + equation + ")"
|
||||
"Fitted_Model(" + self.to_display_text + ")"
|
||||
|
||||
## PRIVATE
|
||||
Convert to a display representation of this Fitted_Model.
|
||||
to_display_text : Text
|
||||
to_display_text self = case self of
|
||||
Fitted_Model.Linear slope intercept _ -> slope.to_text + " * X + " + intercept.to_text
|
||||
Fitted_Model.Exponential a b _ -> a.to_text + " * (" + b.to_text + " * X).exp"
|
||||
Fitted_Model.Logarithmic a b _ -> a.to_text + " * X.ln + " + b.to_text
|
||||
Fitted_Model.Power a b _ -> a.to_text + " * X ^ " + b.to_text
|
||||
|
||||
## Use the model to predict a value.
|
||||
predict : Number -> Number
|
||||
@ -108,7 +122,6 @@ type Fit_Error
|
||||
Error message
|
||||
|
||||
## PRIVATE
|
||||
|
||||
Converts the `Fit_Error` to a human-readable representation.
|
||||
to_display_text : Text
|
||||
to_display_text self = "Could not fit the model: " + self.message.to_text
|
||||
|
@ -23,6 +23,15 @@ type Case_Sensitivity
|
||||
- locale: The locale used for the comparison.
|
||||
Insensitive locale=Locale.default
|
||||
|
||||
## PRIVATE
|
||||
Convert Case_Sensitivity to a friendly string.
|
||||
to_display_text : Text
|
||||
to_display_text self = case self of
|
||||
Case_Sensitivity.Default -> "Default"
|
||||
Case_Sensitivity.Sensitive -> "Sensitive"
|
||||
Case_Sensitivity.Insensitive locale ->
|
||||
if locale == Locale.default then "Insensitive" else "Insensitive(" + locale.to_text + ")"
|
||||
|
||||
## PRIVATE
|
||||
Creates a Java `TextFoldingStrategy` from the case sensitivity setting.
|
||||
folding_strategy : Case_Sensitivity -> TextFoldingStrategy
|
||||
@ -43,7 +52,7 @@ type Case_Sensitivity
|
||||
Case_Sensitivity.Insensitive locale -> case locale == Locale.default of
|
||||
True -> True
|
||||
False ->
|
||||
msg = "Custom locales are not supported for this operationc."
|
||||
msg = "Custom locales are not supported for this operation."
|
||||
Error.throw (Illegal_Argument.Error msg)
|
||||
|
||||
## PRIVATE
|
||||
|
@ -107,3 +107,8 @@ type Encoding
|
||||
## Encoding for Vietnamese (Windows).
|
||||
windows_1258 : Encoding
|
||||
windows_1258 = Encoding.Value "windows-1258"
|
||||
|
||||
## PRIVATE
|
||||
Convert Encoding to a friendly string.
|
||||
to_display_text : Text
|
||||
to_display_text self = self.character_set
|
||||
|
@ -78,3 +78,8 @@ type Regex_Syntax_Error
|
||||
Arguments:
|
||||
- message: A description of the erroneous syntax.
|
||||
Error message
|
||||
|
||||
## PRIVATE
|
||||
Provides a human-readable representation of the `Regex_Syntax_Error`.
|
||||
to_display_text : Text
|
||||
to_display_text self = "Regex Syntax Error:" + self.message
|
||||
|
@ -95,6 +95,12 @@ type Span
|
||||
to_utf_16_span self =
|
||||
Utf_16_Span.Value (range_to_char_indices self.parent self.range) self.parent
|
||||
|
||||
## PRIVATE
|
||||
Convert to a display representation of this Span.
|
||||
to_display_text : Text
|
||||
to_display_text self = self.text
|
||||
|
||||
|
||||
type Utf_16_Span
|
||||
## A representation of a span of UTF-16 code units in Enso's `Text` type.
|
||||
|
||||
@ -165,6 +171,11 @@ type Utf_16_Span
|
||||
grapheme_end = grapheme_last + 1
|
||||
Span.Value (grapheme_first.up_to grapheme_end) self.parent
|
||||
|
||||
## PRIVATE
|
||||
Convert to a display representation of this Span.
|
||||
to_display_text : Text
|
||||
to_display_text self = self.text
|
||||
|
||||
## PRIVATE
|
||||
Utility function taking a range pointing at grapheme clusters and converting
|
||||
to a range on the underlying code units.
|
||||
|
@ -1,5 +1,6 @@
|
||||
import project.Data.Locale.Locale
|
||||
import project.Data.Text.Case_Sensitivity.Case_Sensitivity
|
||||
import project.Data.Text.Text
|
||||
import project.Nothing.Nothing
|
||||
|
||||
from project.Data.Boolean import Boolean, True, False
|
||||
@ -46,3 +47,9 @@ type Text_Ordering
|
||||
Text_Ordering.Default _ -> Case_Sensitivity.Default
|
||||
Text_Ordering.Case_Sensitive _ -> Case_Sensitivity.Sensitive
|
||||
Text_Ordering.Case_Insensitive locale _ -> Case_Sensitivity.Insensitive locale
|
||||
|
||||
## PRIVATE
|
||||
Convert Text_Ordering to a friendly string.
|
||||
to_display_text : Text
|
||||
to_display_text self =
|
||||
self.case_sensitivity.to_display_text + if self.sort_digits_as_numbers then " (Natural Order)" else ""
|
||||
|
@ -40,6 +40,15 @@ type Text_Sub_Range
|
||||
Select an empty string if the input does not contain `delimiter`.
|
||||
After_Last (delimiter : Text)
|
||||
|
||||
## PRIVATE
|
||||
Convert to a display representation of this Index_Sub_Range.
|
||||
to_display_text : Text
|
||||
to_display_text self = case self of
|
||||
Text_Sub_Range.Before delimiter -> "Before " + delimiter.to_display_text
|
||||
Text_Sub_Range.Before_Last delimiter -> "Before Last " + delimiter.to_display_text
|
||||
Text_Sub_Range.After delimiter -> "After " + delimiter.to_display_text
|
||||
Text_Sub_Range.After_Last delimiter -> "After Last " + delimiter.to_display_text
|
||||
|
||||
type Codepoint_Ranges
|
||||
## PRIVATE
|
||||
A list of codepoint ranges corresponding to the matched parts of the
|
||||
|
@ -543,6 +543,12 @@ type Date
|
||||
_ ->
|
||||
Error.throw (Illegal_Argument.Error "Illegal period argument")
|
||||
|
||||
## PRIVATE
|
||||
Convert to a display representation of this Date.
|
||||
to_display_text : Text
|
||||
to_display_text self =
|
||||
self.format "yyyy-MM-dd"
|
||||
|
||||
## PRIVATE
|
||||
Convert to a JS_Object representing this Date.
|
||||
|
||||
@ -596,7 +602,6 @@ type Date
|
||||
format : Text -> Text
|
||||
format self pattern = Time_Utils.local_date_format self pattern
|
||||
|
||||
|
||||
## PRIVATE
|
||||
week_days_between start end =
|
||||
## We split the interval into 3 periods: the first week (containing the
|
||||
|
@ -589,6 +589,13 @@ type Date_Time
|
||||
Time_Utils.datetime_adjust self Time_Utils.AdjustOp.MINUS period.internal_period
|
||||
ensure_in_epoch result result
|
||||
|
||||
## PRIVATE
|
||||
Convert to a display representation of this Date_Time.
|
||||
to_display_text : Text
|
||||
to_display_text self =
|
||||
time_format = if self.nanosecond == 0 then "HH:mm:ss" else "HH:mm:ss.n"
|
||||
self.format "yyyy-MM-dd "+time_format+" VV"
|
||||
|
||||
## PRIVATE
|
||||
Convert to a JavaScript Object representing a Date_Time.
|
||||
|
||||
|
@ -4,6 +4,8 @@ import project.Data.Numbers.Decimal
|
||||
import project.Data.Numbers.Integer
|
||||
import project.Data.Ordering.Comparable
|
||||
import project.Data.Pair.Pair
|
||||
import project.Data.Text.Extensions
|
||||
import project.Data.Text.Text
|
||||
import project.Data.Time.Date_Time.Date_Time
|
||||
import project.Data.Time.Period.Period
|
||||
import project.Data.Vector.Vector
|
||||
@ -262,3 +264,17 @@ type Duration
|
||||
if self.milliseconds==0 . not then b.append ["milliseconds", self.milliseconds]
|
||||
if self.nanoseconds==0 . not then b.append ["nanoseconds", self.nanoseconds]
|
||||
JS_Object.from_pairs b.to_vector
|
||||
|
||||
## PRIVATE
|
||||
Convert Duration to a friendly string.
|
||||
to_display_text : Text
|
||||
to_display_text self = if self == Duration.zero then "0s" else
|
||||
h = if self.hours == 0 then "" else self.hours.to_text + "h "
|
||||
|
||||
s = if self.seconds == 0 && self.nanoseconds == 0 then "" else
|
||||
seconds = self.seconds + self.nanoseconds/1000000000
|
||||
seconds.format "00.##########" + "s"
|
||||
|
||||
m = if self.minutes == 0 && (h=="" || s=="") then "" else self.minutes.to_text + "m "
|
||||
|
||||
(h+m+s).trim
|
||||
|
@ -1,12 +1,14 @@
|
||||
import project.Any.Any
|
||||
import project.Data.Numbers.Integer
|
||||
import project.Data.Ordering.Comparable
|
||||
import project.Data.Text.Extensions
|
||||
import project.Data.Text.Text
|
||||
import project.Data.Time.Date.Date
|
||||
import project.Data.Time.Duration.Duration
|
||||
import project.Data.Ordering.Comparable
|
||||
import project.Data.Text.Text
|
||||
import project.Error.Error
|
||||
import project.Errors.Illegal_Argument.Illegal_Argument
|
||||
import project.Errors.Time_Error.Time_Error
|
||||
import project.Math
|
||||
import project.Meta
|
||||
import project.Nothing.Nothing
|
||||
import project.Panic.Panic
|
||||
@ -128,3 +130,17 @@ type Period
|
||||
case err of
|
||||
DateTimeException -> Error.throw Time_Error.Error "Period subtraction failed"
|
||||
ArithmeticException -> Error.throw Illegal_Argument.Error "Arithmetic error"
|
||||
|
||||
## PRIVATE
|
||||
Convert Period to a friendly string.
|
||||
to_display_text : Text
|
||||
to_display_text self = if self == Period.new then "0D" else
|
||||
years = self.years + (self.months/12).floor
|
||||
y = if years == 0 then "" else years.to_text + "Y "
|
||||
|
||||
d = if self.days == 0 then "" else self.days.to_text + "D "
|
||||
|
||||
months = self.months % 12
|
||||
m = if months == 0 && (y=="" || d=="") then "" else months.to_text + "M "
|
||||
|
||||
(y + m + d) . trim
|
||||
|
@ -300,6 +300,13 @@ type Time_Of_Day
|
||||
cons_pair = ["constructor", "new"]
|
||||
JS_Object.from_pairs [type_pair, cons_pair, ["hour", self.hour], ["minute", self.minute], ["second", self.second], ["nanosecond", self.nanosecond]]
|
||||
|
||||
## PRIVATE
|
||||
Convert to a display representation of this Time_Of_Day.
|
||||
to_display_text : Text
|
||||
to_display_text self =
|
||||
if self.nanosecond == 0 then self.format "HH:mm:ss" else
|
||||
self.format "HH:mm:ss.n"
|
||||
|
||||
## Format this time of day using the provided formatter pattern.
|
||||
|
||||
Arguments:
|
||||
|
@ -170,3 +170,8 @@ type Time_Zone
|
||||
type_pair = ["type", "Time_Zone"]
|
||||
cons_pair = ["constructor", "new"]
|
||||
JS_Object.from_pairs [type_pair, cons_pair, ["id", self.zone_id]]
|
||||
|
||||
## PRIVATE
|
||||
Convert to a display representation of this Time_Zone.
|
||||
to_display_text : Text
|
||||
to_display_text self = self.to_text
|
||||
|
@ -3,6 +3,7 @@ import project.Error.Error
|
||||
import project.Meta
|
||||
import project.Nothing.Nothing
|
||||
import project.Panic.Panic
|
||||
|
||||
from project.Data.Boolean import True, False
|
||||
|
||||
polyglot java import java.lang.ClassCastException
|
||||
@ -161,7 +162,9 @@ type No_Such_Method
|
||||
## PRIVATE
|
||||
Convert the No_Such_Method error to a human-readable format.
|
||||
to_display_text : Text
|
||||
to_display_text self = "Method `"+self.method_name+"` of "+self.target.to_display_text+" could not be found."
|
||||
to_display_text self =
|
||||
target_type_name = if Meta.is_polyglot self.target then self.target.to_display_text else (Meta.type_of self.target).to_display_text
|
||||
"Method `"+self.method_name+"` of type "+target_type_name+" could not be found."
|
||||
|
||||
@Builtin_Type
|
||||
type No_Such_Field
|
||||
@ -174,6 +177,12 @@ type No_Such_Field
|
||||
- field_name: The name of the field that was being accessed.
|
||||
Error value field_name
|
||||
|
||||
## PRIVATE
|
||||
Convert the No_Such_Method error to a human-readable format.
|
||||
to_display_text : Text
|
||||
to_display_text self =
|
||||
value_type_name = if Meta.is_polyglot self.value then self.value.to_display_text else (Meta.type_of self.value).to_display_text
|
||||
"Field `"+self.field_name+"` of "+value_type_name+" could not be found."
|
||||
|
||||
@Builtin_Type
|
||||
type Module_Not_In_Package_Error
|
||||
@ -214,7 +223,7 @@ type Incomparable_Values
|
||||
to_display_text : Text
|
||||
to_display_text self =
|
||||
case self.left.is_nothing && self.right.is_nothing of
|
||||
True -> "Incomparable_Values.Error"
|
||||
True -> "Incomparable_Values"
|
||||
False -> "Cannot compare `" + self.left.to_text + "` with `" + self.right.to_text + "`"
|
||||
|
||||
## PRIVATE
|
||||
|
@ -12,7 +12,6 @@ type Project_Description
|
||||
- prim_config: The primitive config of the project.
|
||||
Value prim_root_file prim_config
|
||||
|
||||
|
||||
## Returns the root directory of the project.
|
||||
|
||||
> Example
|
||||
|
@ -1,4 +1,5 @@
|
||||
import project.Data.Boolean.Boolean
|
||||
import project.Data.Text.Text
|
||||
|
||||
type HTTP_Status_Code
|
||||
## 100 Continue.
|
||||
@ -170,3 +171,49 @@ type HTTP_Status_Code
|
||||
## Does the status code represent a successful response?
|
||||
is_success : Boolean
|
||||
is_success self = self.code >= 200 && self.code < 300
|
||||
|
||||
## PRIVATE
|
||||
Convert to a display representation of this HTTP_Status_Code.
|
||||
to_display_text : Text
|
||||
to_display_text self = case self.code of
|
||||
100 -> "Continue"
|
||||
101 -> "Switching Protocols"
|
||||
200 -> "OK"
|
||||
201 -> "Created"
|
||||
202 -> "Accepted"
|
||||
203 -> "Non-Authoritative Information"
|
||||
204 -> "No Content"
|
||||
205 -> "Reset Content"
|
||||
206 -> "Partial Content"
|
||||
300 -> "Multiple Choices"
|
||||
301 -> "Moved Permanently"
|
||||
302 -> "Found"
|
||||
303 -> "See Other"
|
||||
304 -> "Not Modified"
|
||||
305 -> "Use Proxy"
|
||||
307 -> "Temporary Redirect"
|
||||
400 -> "Bad Request"
|
||||
401 -> "Unauthorized"
|
||||
402 -> "Payment Required"
|
||||
403 -> "Forbidden"
|
||||
404 -> "Not Found"
|
||||
405 -> "Method Not Allowed"
|
||||
406 -> "Not Acceptable"
|
||||
407 -> "Proxy Authentication Required"
|
||||
408 -> "Request Timeout"
|
||||
409 -> "Conflict"
|
||||
410 -> "Gone"
|
||||
411 -> "Length Required"
|
||||
412 -> "Precondition Failed"
|
||||
413 -> "Request Entity Too Large"
|
||||
414 -> "Request-URI Too Long"
|
||||
415 -> "Unsupported Media Type"
|
||||
416 -> "Requested Range Not Satisfiable"
|
||||
417 -> "Expectation Failed"
|
||||
500 -> "Internal Server Error"
|
||||
501 -> "Not Implemented"
|
||||
502 -> "Bad Gateway"
|
||||
503 -> "Service Unavailable"
|
||||
504 -> "Gateway Timeout"
|
||||
505 -> "HTTP Version Not Supported"
|
||||
_ -> "HTTP Status Code: " + self.code.to_text
|
||||
|
@ -173,6 +173,12 @@ type Header
|
||||
text_plain : Header
|
||||
text_plain = Header.content_type "text/plain"
|
||||
|
||||
|
||||
## PRIVATE
|
||||
Convert to a display representation of this Header.
|
||||
to_display_text : Text
|
||||
to_display_text self = self.name + ": " + self.value.to_display_text
|
||||
|
||||
## PRIVATE
|
||||
type Header_Comparator
|
||||
## PRIVATE
|
||||
|
@ -188,6 +188,11 @@ type URI
|
||||
to_text : Text
|
||||
to_text self = self.internal_uri.toString
|
||||
|
||||
## PRIVATE
|
||||
Convert to a display representation of this URI.
|
||||
to_display_text : Text
|
||||
to_display_text self = self.to_text.to_display_text
|
||||
|
||||
## PRIVATE
|
||||
Convert to a JavaScript Object representing this URI.
|
||||
|
||||
|
@ -3,6 +3,8 @@ import project.Data.Boolean.Boolean
|
||||
import project.Data.Numbers.Integer
|
||||
import project.Data.Numbers.Decimal
|
||||
import project.Data.Vector.Vector
|
||||
import project.Data.Json.JS_Object
|
||||
import project.Data.Text.Text
|
||||
import project.Error.Error
|
||||
import project.Errors.Illegal_Argument.Illegal_Argument
|
||||
import project.System
|
||||
@ -53,6 +55,17 @@ type Random_Number_Generator
|
||||
if range < Java_Integer.MAX_VALUE then min + (self.java_random.nextInt range) else
|
||||
Error.throw (Illegal_Argument.Error "Currently only integer ranges of up to 2^31-1 are supported.")
|
||||
|
||||
## PRIVATE
|
||||
Serialise to JS_Object
|
||||
to_js_object : JS_Object
|
||||
to_js_object self =
|
||||
JS_Object.from_pairs [["type", "Random_Number_Generator"], ["constructor", "new"]]
|
||||
|
||||
## PRIVATE
|
||||
Convert to a display representation of this Random_Number_Generator.
|
||||
to_display_text : Text
|
||||
to_display_text self = "Random_Number_Generator"
|
||||
|
||||
## Returns a new vector containing a random sample of the input vector, without
|
||||
replacement.
|
||||
|
||||
|
@ -676,6 +676,11 @@ type File
|
||||
to_text : Text
|
||||
to_text self = self.absolute . path
|
||||
|
||||
## PRIVATE
|
||||
Convert to a display representation of this File.
|
||||
to_display_text : Text
|
||||
to_display_text self = self.to_text
|
||||
|
||||
## PRIVATE
|
||||
An output stream, allowing for interactive writing of contents into an
|
||||
open file.
|
||||
|
@ -1,5 +1,6 @@
|
||||
import project.Data.Vector.Vector
|
||||
import project.Data.Boolean.Boolean
|
||||
import project.Data.Text.Text
|
||||
import project.Data.Vector.Vector
|
||||
|
||||
polyglot java import java.nio.file.attribute.PosixFilePermission
|
||||
|
||||
@ -108,3 +109,12 @@ type File_Permissions
|
||||
others.append Permission.Execute
|
||||
|
||||
File_Permissions.Value owner.to_vector group.to_vector others.to_vector
|
||||
|
||||
## PRIVATE
|
||||
Convert to a display representation of this File_Permissions.
|
||||
to_display_text : Text
|
||||
to_display_text self =
|
||||
owner = "Owner: " + (if self.owner_read then "r" else "-") + (if self.owner_write then "w" else "-") + (if self.owner_execute then "x" else "-")
|
||||
group = "Group: " + (if self.group_read then "r" else "-") + (if self.group_write then "w" else "-") + (if self.group_execute then "x" else "-")
|
||||
other = "Other: " + (if self.others_read then "r" else "-") + (if self.others_write then "w" else "-") + (if self.others_execute then "x" else "-")
|
||||
owner + ", " + group + ", " + other
|
||||
|
@ -1,4 +1,5 @@
|
||||
import project.Data.Numbers.Integer
|
||||
import project.Data.Text.Text
|
||||
|
||||
## The exit codes that the process can return.
|
||||
type Exit_Code
|
||||
@ -39,3 +40,10 @@ type Exit_Code
|
||||
to_number self = case self of
|
||||
Exit_Code.Success -> 0
|
||||
Exit_Code.Failure code -> code
|
||||
|
||||
## PRIVATE
|
||||
Convert to a display representation of this Exit_Code.
|
||||
to_display_text : Text
|
||||
to_display_text self = case self of
|
||||
Exit_Code.Success -> "Success"
|
||||
Exit_Code.Failure code -> "Failure " + code.to_display_text
|
||||
|
@ -78,3 +78,10 @@ type Process_Builder
|
||||
type Process_Result
|
||||
## PRIVATE
|
||||
Value exit_code:Exit_Code stdout:Text stderr:Text
|
||||
|
||||
## PRIVATE
|
||||
Convert to a display representation of this Process_Result.
|
||||
to_display_text : Text
|
||||
to_display_text self = case self.exit_code of
|
||||
Exit_Code.Success -> "Success(" + self.stdout.to_display_text + ")"
|
||||
_ -> self.exit_code.to_display_text + "(" + self.stderr.to_display_text + ")"
|
||||
|
@ -28,7 +28,7 @@ type Warning
|
||||
|
||||
## ADVANCED
|
||||
Are any warnings attached to the value?
|
||||
has_warnings : Any -> Boolean
|
||||
has_warnings : Any -> Any -> Boolean
|
||||
has_warnings value warning_type=Any =
|
||||
Warning.get_all value . any (w-> w.value.is_a warning_type)
|
||||
|
||||
@ -36,7 +36,7 @@ type Warning
|
||||
|
||||
Arguments:
|
||||
- warning_type: The type to remove if attached to the value. Defaults to all warnings.
|
||||
remove_warnings : Any -> Any
|
||||
remove_warnings : Any -> Any -> Any
|
||||
remove_warnings value warning_type=Any =
|
||||
Warning.detach_selected_warnings value (w-> w.is_a warning_type) . first
|
||||
|
||||
|
@ -1497,6 +1497,7 @@ type Table
|
||||
suffixing strategy.
|
||||
parse_to_columns : Text | Integer -> Text -> Case_Sensitivity -> Boolean -> Problem_Behavior -> Table
|
||||
parse_to_columns self column pattern="." case_sensitivity=Case_Sensitivity.Sensitive parse_values=True on_problems=Report_Error =
|
||||
_ = [column, pattern, case_sensitivity, parse_values, on_problems]
|
||||
Error.throw (Unsupported_Database_Operation.Error "Table.parse_to_columns is not implemented yet for the Database backends.")
|
||||
|
||||
## PRIVATE
|
||||
|
@ -300,7 +300,6 @@ type Value_Type
|
||||
to_js_object : JS_Object
|
||||
to_js_object self =
|
||||
constructor_name = Meta.meta self . constructor . name
|
||||
display_text = self.to_display_text
|
||||
additional_fields = case self of
|
||||
Value_Type.Integer size ->
|
||||
[["bits", size.to_bits]]
|
||||
@ -316,7 +315,7 @@ type Value_Type
|
||||
[["type_name", type_name]]
|
||||
_ -> []
|
||||
JS_Object.from_pairs <|
|
||||
[["type", "Value_Type"], ["constructor", constructor_name], ["_display_text_", display_text]] + additional_fields
|
||||
[["type", "Value_Type"], ["constructor", constructor_name]] + additional_fields
|
||||
|
||||
## The type representing inferring the column type automatically based on values
|
||||
present in the column.
|
||||
|
@ -50,7 +50,7 @@ type Too_Many_Column_Names_Provided
|
||||
|
||||
## One or more column names were invalid during a rename operation.
|
||||
type Invalid_Output_Column_Names
|
||||
Error (column_names : [Text])
|
||||
Error (column_names : Vector Text)
|
||||
|
||||
## PRIVATE
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
from Standard.Base import all
|
||||
import Standard.Base.Data.Vector.Builder
|
||||
|
||||
import Standard.Table.Data.Table.Table as Dataframe_Table
|
||||
import Standard.Table.Data.Column.Column as Dataframe_Column
|
||||
@ -21,46 +22,109 @@ import project.Helpers
|
||||
prepare_visualization : Any -> Integer -> Text
|
||||
prepare_visualization y max_rows=1000 = Helpers.recover_errors <|
|
||||
x = Warning.set y []
|
||||
case x of
|
||||
|
||||
result = case x of
|
||||
_ : Vector -> make_json_for_vector x max_rows
|
||||
_ : Array -> prepare_visualization x.to_vector max_rows
|
||||
_ : Map -> make_json_for_map x max_rows
|
||||
_ : JS_Object -> make_json_for_js_object x max_rows
|
||||
_ : Dataframe_Column -> prepare_visualization x.to_table max_rows
|
||||
_ : Dataframe_Table ->
|
||||
dataframe = x.take (First max_rows)
|
||||
dataframe = x.take max_rows
|
||||
all_rows_count = x.row_count
|
||||
included_rows = dataframe.row_count
|
||||
index = Dataframe_Column.from_vector "#" (Vector.new included_rows i->i)
|
||||
|
||||
make_json dataframe [index] all_rows_count
|
||||
|
||||
index = Dataframe_Column.from_vector "#" (Vector.new dataframe.row_count i->i)
|
||||
make_json_for_table dataframe [index] all_rows_count
|
||||
_ : Database_Column -> prepare_visualization x.to_table max_rows
|
||||
_ : Database_Table ->
|
||||
df = x.read max_rows
|
||||
dataframe = x.read max_rows
|
||||
all_rows_count = x.row_count
|
||||
|
||||
make_json df [] all_rows_count
|
||||
|
||||
# We display columns as 1-column tables.
|
||||
_ : Dataframe_Column ->
|
||||
prepare_visualization x.to_table max_rows
|
||||
_ : Database_Column ->
|
||||
prepare_visualization x.to_table max_rows
|
||||
|
||||
# TODO [RW] Should we truncate Vectors?
|
||||
# We also visualize Vectors and arrays
|
||||
_ : Vector ->
|
||||
truncated = x.take (First max_rows)
|
||||
JS_Object.from_pairs [["json", truncated], ["all_rows_count", x.length]] . to_text
|
||||
_ : Array ->
|
||||
prepare_visualization (Vector.from_polyglot_array x) max_rows
|
||||
|
||||
# Serialize Maps
|
||||
_ : Map ->
|
||||
map_vector = Warning.clear (x.to_vector.take max_rows)
|
||||
header = ["header", ["key", "value"]]
|
||||
data = ["data", [map_vector.map .first, map_vector.map .second]]
|
||||
all_rows = ["all_rows_count", x.size]
|
||||
JS_Object.from_pairs [header, data, all_rows] . to_text
|
||||
|
||||
# Anything else will be visualized with the JSON or matrix visualization
|
||||
make_json_for_table dataframe [] all_rows_count
|
||||
_ ->
|
||||
JS_Object.from_pairs [["json", x]] . to_text
|
||||
js_value = x.to_js_object
|
||||
value = if js_value.is_a JS_Object . not then js_value else
|
||||
pairs = [['_display_text_', x.to_display_text]] + js_value.field_names.map f-> [f, make_json_for_value (js_value.get f)]
|
||||
JS_Object.from_pairs pairs
|
||||
JS_Object.from_pairs [["json", value]]
|
||||
|
||||
result.to_text
|
||||
|
||||
## Column Limit
|
||||
max_columns = 250
|
||||
|
||||
## PRIVATE
|
||||
Render Vector to JSON
|
||||
make_json_for_vector : Vector -> Integer -> JS_Object
|
||||
make_json_for_vector vector max_rows =
|
||||
all_rows = ["all_rows_count", vector.length]
|
||||
truncated = vector.take max_rows
|
||||
|
||||
matrix = make_json_for_matrix (Vector.new_builder truncated.length) truncated
|
||||
if matrix.is_nothing.not then JS_Object.from_pairs [["type", "Matrix"], all_rows, ["json", matrix], ["column_count", matrix.fold 0 c->v-> if v.is_nothing then c else c.max v.length]] else
|
||||
object_matrix = make_json_for_object_matrix (Vector.new_builder truncated.length) truncated
|
||||
if object_matrix.is_nothing.not then JS_Object.from_pairs [["type", "Object_Matrix"], all_rows, ["json", object_matrix]] else
|
||||
JS_Object.from_pairs [["type", "Vector"], all_rows, ["json", truncated.map make_json_for_value]]
|
||||
|
||||
## PRIVATE
|
||||
Render Vector of Vector / Array to JSON
|
||||
make_json_for_matrix : Builder -> Vector -> Integer -> Vector | Nothing
|
||||
make_json_for_matrix current vector idx=0 = if idx == vector.length then current.to_vector else
|
||||
row = vector.at idx
|
||||
to_append = case row of
|
||||
Nothing -> Nothing
|
||||
_ : Vector -> row.take max_columns . map make_json_for_value
|
||||
_ : Array -> row.to_vector.take max_columns . map make_json_for_value
|
||||
_ -> False
|
||||
if to_append == False then Nothing else
|
||||
next = current.append to_append
|
||||
@Tail_Call make_json_for_matrix next vector idx+1
|
||||
|
||||
## PRIVATE
|
||||
Render Vector of Objects to JSON
|
||||
make_json_for_object_matrix : Builder -> Vector -> Integer -> Vector | Nothing
|
||||
make_json_for_object_matrix current vector idx=0 = if idx == vector.length then current.to_vector else
|
||||
row = vector.at idx
|
||||
to_append = case row of
|
||||
Nothing -> Nothing
|
||||
_ : Date -> False
|
||||
_ : Time_Of_Day -> False
|
||||
_ : Date_Time -> False
|
||||
_ : Duration -> False
|
||||
_ : Period -> False
|
||||
_ : Map ->
|
||||
pairs = row.keys.map k-> [k.to_text, make_json_for_value (row.get k)]
|
||||
JS_Object.from_pairs pairs
|
||||
_ ->
|
||||
js_object = row.to_js_object
|
||||
if js_object.is_a JS_Object . not then False else
|
||||
if js_object.field_names.sort == ["type" , "constructor"] then False else
|
||||
pairs = js_object.field_names.map f-> [f, make_json_for_value (js_object.get f)]
|
||||
JS_Object.from_pairs pairs
|
||||
if to_append == False then Nothing else
|
||||
next = current.append to_append
|
||||
@Tail_Call make_json_for_object_matrix next vector idx+1
|
||||
|
||||
## PRIVATE
|
||||
Render Map to JSON
|
||||
make_json_for_map : Map -> Integer -> JS_Object
|
||||
make_json_for_map map max_items =
|
||||
header = ["header", ["key", "value"]]
|
||||
all_rows = ["all_rows_count", map.size]
|
||||
map_vector = Warning.clear (map.to_vector.take max_items)
|
||||
mapped = map_vector . map p-> [p.first.to_text, make_json_for_value p.second]
|
||||
data = ["data", [mapped.map .first, mapped.map .second]]
|
||||
JS_Object.from_pairs [header, data, all_rows, ["type", "Map"]]
|
||||
|
||||
## PRIVATE
|
||||
Render JS_Object to JSON
|
||||
make_json_for_js_object : JS_Object -> Integer -> JS_Object
|
||||
make_json_for_js_object js_object max_items =
|
||||
fields = js_object.field_names
|
||||
header = ["header", ["key", "value"]]
|
||||
all_rows = ["all_rows_count", fields.length]
|
||||
map_vector = Warning.clear (fields.take max_items)
|
||||
mapped = map_vector . map p-> [p, make_json_for_value (js_object.get p)]
|
||||
data = ["data", [mapped.map .first, mapped.map .second]]
|
||||
JS_Object.from_pairs [header, data, all_rows, ["type", "Map"]]
|
||||
|
||||
## PRIVATE
|
||||
Creates a JSON representation for the visualizations.
|
||||
@ -73,14 +137,51 @@ prepare_visualization y max_rows=1000 = Helpers.recover_errors <|
|
||||
`dataframe`.
|
||||
- all_rows_count: the number of all rows in the underlying data, useful if
|
||||
only a fragment is displayed.
|
||||
make_json : (Dataframe_Table | Database_Table) -> Vector Dataframe_Column -> Integer -> Text
|
||||
make_json dataframe indices all_rows_count =
|
||||
get_vector c = Warning.set c.to_vector []
|
||||
make_json_for_table : Dataframe_Table -> Vector Dataframe_Column -> Integer -> JS_Object
|
||||
make_json_for_table dataframe indices all_rows_count =
|
||||
get_vector c = Warning.set (c.to_vector.map v-> make_json_for_value v) []
|
||||
columns = dataframe.columns
|
||||
header = ["header", columns.map .name]
|
||||
data = ["data", columns.map get_vector]
|
||||
all_rows = ["all_rows_count", all_rows_count]
|
||||
ixes = ["indices", indices.map get_vector]
|
||||
ixes_header = ["indices_header", indices.map .name]
|
||||
pairs = [header, data, all_rows, ixes, ixes_header]
|
||||
JS_Object.from_pairs pairs . to_text
|
||||
pairs = [header, data, all_rows, ixes, ixes_header, ["type", "Table"]]
|
||||
JS_Object.from_pairs pairs
|
||||
|
||||
## PRIVATE
|
||||
Create JSON serialization of values for the table.
|
||||
make_json_for_value : Any -> Integer -> Text
|
||||
make_json_for_value val level=0 = case val of
|
||||
Nothing -> Nothing
|
||||
_ : Text -> val
|
||||
_ : Number ->
|
||||
js_version = val.to_js_object
|
||||
if js_version.is_a JS_Object . not then js_version else
|
||||
pairs = [['_display_text_', val.to_display_text]] + js_version.field_names.map f-> [f, js_version.get f]
|
||||
JS_Object.from_pairs pairs
|
||||
_ : Boolean -> val
|
||||
_ : Vector ->
|
||||
if level != 0 then "[… "+val.length.to_text+" items]" else
|
||||
truncated = val.take 5 . map v-> (make_json_for_value v level+1).to_text
|
||||
prepared = if val.length > 5 then truncated + ["… " + (val.length - 5).to_text+ " items"] else truncated
|
||||
"[" + (prepared.join ", ") + "]"
|
||||
_ : Array -> make_json_for_value val.to_vector level
|
||||
_ : Map ->
|
||||
if level != 0 then "{… "+val.size.to_text+" items}" else
|
||||
truncated = val.keys.take 5 . map k-> k.to_text + ": " + (make_json_for_value (val.get k) level+1).to_text
|
||||
prepared = if val.length > 5 then truncated + ["… " + (val.length - 5).to_text+ " items"] else truncated
|
||||
"{" + (prepared.join ", ") + "}"
|
||||
_ : Dataframe_Column -> make_json_for_value val.to_table level
|
||||
_ : Database_Column -> make_json_for_value val.to_table level
|
||||
_ : Dataframe_Table ->
|
||||
if level != 0 then "Table{" + val.row_count + " rows x " + val.column_count + " columns}" else
|
||||
truncated = val.columns.take 5 . map _.name
|
||||
prepared = if val.column_count > 5 then truncated + ["… " + (val.column_count - 5).to_text+ " more"] else truncated
|
||||
"Table{" + val.row_count.to_text + " rows x [" + (prepared.join ", ") + "]}"
|
||||
_ : Database_Table ->
|
||||
if level != 0 then "Table{" + val.row_count + " rows x " + val.column_count + " columns}" else
|
||||
truncated = val.columns.take 5 . map _.name
|
||||
prepared = if val.column_count > 5 then truncated + ["… " + (val.column_count - 5).to_text+ " more"] else truncated
|
||||
"Table{" + val.row_count.to_text + " rows x [" + (prepared.join ", ") + "]}"
|
||||
_ -> val.to_display_text
|
||||
|
@ -2989,7 +2989,7 @@ class RuntimeServerTest
|
||||
contextId,
|
||||
Seq(
|
||||
Api.ExecutionResult.Diagnostic.error(
|
||||
"Type error: expected a function, but got 42 (Integer).",
|
||||
"Type error: expected a function, but got 42.",
|
||||
Some(mainFile),
|
||||
Some(model.Range(model.Position(1, 7), model.Position(1, 19))),
|
||||
None,
|
||||
@ -3136,7 +3136,7 @@ class RuntimeServerTest
|
||||
contextId,
|
||||
Seq(
|
||||
Api.ExecutionResult.Diagnostic.error(
|
||||
"Method `+` of x (Unresolved_Symbol) could not be found.",
|
||||
"Method `+` of type Function could not be found.",
|
||||
Some(mainFile),
|
||||
Some(model.Range(model.Position(3, 14), model.Position(3, 23))),
|
||||
None,
|
||||
@ -3440,7 +3440,7 @@ class RuntimeServerTest
|
||||
contextId,
|
||||
Seq(
|
||||
Api.ExecutionResult.Diagnostic.error(
|
||||
"Method `pi` of Number could not be found.",
|
||||
"Method `pi` of type Number.type could not be found.",
|
||||
Some(mainFile),
|
||||
Some(model.Range(model.Position(3, 7), model.Position(3, 16))),
|
||||
None,
|
||||
|
@ -1733,10 +1733,11 @@ class RuntimeVisualizationsTest
|
||||
Api.Response(
|
||||
requestId,
|
||||
Api.VisualisationExpressionFailed(
|
||||
"Method `does_not_exist` of Main could not be found.",
|
||||
"Method `does_not_exist` of type Main could not be found.",
|
||||
Some(
|
||||
Api.ExecutionResult.Diagnostic.error(
|
||||
message = "Method `does_not_exist` of Main could not be found.",
|
||||
message =
|
||||
"Method `does_not_exist` of type Main could not be found.",
|
||||
stack = Vector(
|
||||
Api.StackTraceElement("<eval>", None, None, None),
|
||||
Api.StackTraceElement("Debug.eval", None, None, None)
|
||||
@ -1817,10 +1818,10 @@ class RuntimeVisualizationsTest
|
||||
contextId,
|
||||
visualisationId,
|
||||
idMain,
|
||||
"Method `visualise_me` of 50 (Integer) could not be found.",
|
||||
"Method `visualise_me` of type Integer could not be found.",
|
||||
Some(
|
||||
Api.ExecutionResult.Diagnostic.error(
|
||||
"Method `visualise_me` of 50 (Integer) could not be found.",
|
||||
"Method `visualise_me` of type Integer could not be found.",
|
||||
None,
|
||||
Some(model.Range(model.Position(0, 5), model.Position(0, 19))),
|
||||
None,
|
||||
@ -1929,10 +1930,10 @@ class RuntimeVisualizationsTest
|
||||
contextId,
|
||||
visualisationId,
|
||||
idMain,
|
||||
"Method `visualise_me` of 51 (Integer) could not be found.",
|
||||
"Method `visualise_me` of type Integer could not be found.",
|
||||
Some(
|
||||
Api.ExecutionResult.Diagnostic.error(
|
||||
"Method `visualise_me` of 51 (Integer) could not be found.",
|
||||
"Method `visualise_me` of type Integer could not be found.",
|
||||
Some(visualisationFile),
|
||||
Some(model.Range(model.Position(1, 11), model.Position(1, 25))),
|
||||
None,
|
||||
@ -2134,10 +2135,10 @@ class RuntimeVisualizationsTest
|
||||
contextId,
|
||||
visualisationId,
|
||||
idMain,
|
||||
"42 (Integer)",
|
||||
"42",
|
||||
Some(
|
||||
Api.ExecutionResult.Diagnostic.error(
|
||||
message = "42 (Integer)",
|
||||
message = "42",
|
||||
file = Some(mainFile),
|
||||
location =
|
||||
Some(model.Range(model.Position(3, 4), model.Position(3, 18))),
|
||||
|
@ -1,6 +1,5 @@
|
||||
package org.enso.interpreter.node.expression.builtin.text;
|
||||
|
||||
import com.ibm.icu.text.BreakIterator;
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.dsl.Cached;
|
||||
import com.oracle.truffle.api.dsl.Fallback;
|
||||
@ -13,6 +12,7 @@ import com.oracle.truffle.api.nodes.Node;
|
||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||
import org.enso.interpreter.node.expression.builtin.text.util.TypeToDisplayTextNode;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
import org.enso.interpreter.runtime.number.EnsoBigInteger;
|
||||
import org.enso.polyglot.common_utils.Core_Text_Utils;
|
||||
|
||||
@BuiltinMethod(type = "Any", name = "to_display_text")
|
||||
@ -35,6 +35,23 @@ public abstract class AnyToDisplayTextNode extends Node {
|
||||
}
|
||||
}
|
||||
|
||||
@Specialization
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
Text convertInteger(long self) {
|
||||
return Text.create(Long.toString(self));
|
||||
}
|
||||
|
||||
@Specialization
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
Text convertDouble(double self) {
|
||||
return Text.create(Double.toString(self));
|
||||
}
|
||||
|
||||
@Specialization
|
||||
Text convertBigInteger(EnsoBigInteger bigInteger) {
|
||||
return Text.create(bigInteger.toString());
|
||||
}
|
||||
|
||||
@Specialization
|
||||
Text convertText(Text self) {
|
||||
final var limit = 80;
|
||||
@ -47,8 +64,8 @@ public abstract class AnyToDisplayTextNode extends Node {
|
||||
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
private static Text takePrefix(Text self, final int limit) {
|
||||
var prefix = Core_Text_Utils.take_prefix(self.toString(), limit);
|
||||
return Text.create(prefix);
|
||||
var prefix = Core_Text_Utils.take_prefix(self.toString(), limit - 2);
|
||||
return Text.create(prefix + " …");
|
||||
}
|
||||
|
||||
@Fallback
|
||||
|
@ -118,7 +118,7 @@ public class TypeMembersTest {
|
||||
v.invokeMember(k);
|
||||
fail("Invoking " + k + " on " + v + " shall fail");
|
||||
} catch (PolyglotException ex) {
|
||||
assertEquals("No_Such_Field.Error", ex.getMessage());
|
||||
assertEquals("Field `" + k + "` of IntList could not be found.", ex.getMessage());
|
||||
}
|
||||
} else {
|
||||
assertNotNull(msg + " - can be invoked", v.invokeMember(k));
|
||||
|
@ -14,7 +14,7 @@ class ImportsTest extends PackageTest {
|
||||
"Overloaded methods" should "not be visible when not imported" in {
|
||||
the[InterpreterException] thrownBy evalTestProject(
|
||||
"TestNonImportedOverloads"
|
||||
) should have message "Method `method` of Mk_X could not be found."
|
||||
) should have message "Method `method` of type X could not be found."
|
||||
}
|
||||
|
||||
"Import statements" should "report errors when they cannot be resolved" in {
|
||||
@ -101,13 +101,13 @@ class ImportsTest extends PackageTest {
|
||||
"Importing module's types" should "not bring extension methods into the scope " in {
|
||||
the[InterpreterException] thrownBy evalTestProject(
|
||||
"Test_Extension_Methods_Failure"
|
||||
) should have message "Method `foo` of 1 (Integer) could not be found."
|
||||
) should have message "Method `foo` of type Integer could not be found."
|
||||
}
|
||||
|
||||
"Compiler" should "detect name conflicts preventing users from importing submodules" in {
|
||||
the[InterpreterException] thrownBy evalTestProject(
|
||||
"TestSubmodulesNameConflict"
|
||||
) should have message "Method `c_mod_method` of C could not be found."
|
||||
) should have message "Method `c_mod_method` of type C.type could not be found."
|
||||
val outLines = consumeOut
|
||||
outLines(2) should include
|
||||
"Declaration of type C shadows module local.TestSubmodulesNameConflict.A.B.C making it inaccessible via a qualified name."
|
||||
@ -183,7 +183,7 @@ class ImportsTest extends PackageTest {
|
||||
"Fully qualified names" should "detect conflicts with the exported types sharing the namespace" in {
|
||||
the[InterpreterException] thrownBy evalTestProject(
|
||||
"Test_Fully_Qualified_Name_Conflict"
|
||||
) should have message "Method `Foo` of Atom could not be found."
|
||||
) should have message "Method `Foo` of type Atom.type could not be found."
|
||||
val outLines = consumeOut
|
||||
outLines should have length 3
|
||||
outLines(
|
||||
|
@ -107,7 +107,7 @@ class MethodsTest extends InterpreterTest {
|
||||
|""".stripMargin
|
||||
the[InterpreterException] thrownBy eval(
|
||||
code
|
||||
) should have message "Method `foo` of 7 (Integer) could not be found."
|
||||
) should have message "Method `foo` of type Integer could not be found."
|
||||
}
|
||||
|
||||
"be callable for any type when defined on Any" in {
|
||||
@ -216,7 +216,7 @@ class MethodsTest extends InterpreterTest {
|
||||
|""".stripMargin
|
||||
the[InterpreterException] thrownBy eval(
|
||||
code
|
||||
) should have message "Method `new` of Mk_Foo could not be found."
|
||||
) should have message "Method `new` of type Foo could not be found."
|
||||
}
|
||||
|
||||
"not be callable on Nothing when non-static" in {
|
||||
|
@ -131,10 +131,10 @@ class TextTest extends InterpreterTest {
|
||||
"Syntax error: foo.",
|
||||
"Type error: expected `myvar` to be Nothing, but got List.",
|
||||
"Compile error: error :(.",
|
||||
"Inexhaustive pattern match: no branch matches 32 (Integer).",
|
||||
"Inexhaustive pattern match: no branch matches 32.",
|
||||
"Arithmetic error: cannot frobnicate quaternions.",
|
||||
"Type error: expected `that` to be Number, but got Text.",
|
||||
"Type error: expected a function, but got 7 (Integer).",
|
||||
"Type error: expected a function, but got 7.",
|
||||
"Wrong number of arguments. Expected 10, but got 20."
|
||||
)
|
||||
}
|
||||
|
@ -413,6 +413,7 @@ spec =
|
||||
pUS2.to_vector . should_equal [1, 123, -1234, 1234567, Nothing]
|
||||
Problems.expect_warning (Invalid_Format.Error "ints" Value_Type.Integer ["12,34,56"]) pUS2
|
||||
|
||||
## Reject minus sign if already seen a bracket form
|
||||
cUS3 = Column.from_vector "ints" ["1", "(000,123)", "-1,234", "1,234,567", "12,34,56"]
|
||||
pUS3 = cUS3.parse type=Value_Type.Integer
|
||||
pUS3.to_vector . should_equal [1, -123, Nothing, 1234567, Nothing]
|
||||
@ -423,6 +424,12 @@ spec =
|
||||
pUS4.to_vector . should_equal [1234, 1234, 1234567, -1234, Nothing]
|
||||
Problems.expect_warning (Invalid_Format.Error "ints" Value_Type.Integer ["($1,234,567)"]) pUS4
|
||||
|
||||
## Reject bracket notation for negative numbers if already seen a minus sign
|
||||
cUS5 = Column.from_vector "ints" ["1", "000123", "-1,234", "1,234,567", "(123,456)"]
|
||||
pUS5 = cUS5.parse type=Value_Type.Integer
|
||||
pUS5.to_vector . should_equal [1, 123, -1234, 1234567, Nothing]
|
||||
Problems.expect_warning (Invalid_Format.Error "ints" Value_Type.Integer ["(123,456)"]) pUS5
|
||||
|
||||
Test.specify "should correctly parse integers in European formats" <|
|
||||
cDE = Column.from_vector "ints" ["1", "000123", "-1.234", "1.234.567", "12.34.56"]
|
||||
pDE = cDE.parse type=Value_Type.Integer
|
||||
@ -470,6 +477,7 @@ spec =
|
||||
pUS2.to_vector . should_equal [1.23, 123, -1234.567, 1234567.789, Nothing]
|
||||
Problems.expect_warning (Invalid_Format.Error "floats" Value_Type.Float ["12,34.56"]) pUS2
|
||||
|
||||
## Reject minus sign if already seen a bracket form
|
||||
cUS3 = Column.from_vector "floats" ["1.23", "(000,123)", "-1,234.567", "1,234,567.789", "12,34.56"]
|
||||
pUS3 = cUS3.parse type=Value_Type.Float
|
||||
pUS3.to_vector . should_equal [1.23, -123, Nothing, 1234567.789, Nothing]
|
||||
@ -480,6 +488,12 @@ spec =
|
||||
pUS4.to_vector . should_equal [12.34, 1234, 1234567.789, -1234.96, Nothing]
|
||||
Problems.expect_warning (Invalid_Format.Error "floats" Value_Type.Float ["($1,234,567)"]) pUS4
|
||||
|
||||
## Reject bracket notation for negative numbers if already seen a minus sign
|
||||
cUS5 = Column.from_vector "floats" ["1.23", "000123", "-1,234.567", "1,234,567.789", "(123,456)"]
|
||||
pUS5 = cUS5.parse type=Value_Type.Float
|
||||
pUS5.to_vector . should_equal [1.23, 123, -1234.567, 1234567.789, Nothing]
|
||||
Problems.expect_warning (Invalid_Format.Error "floats" Value_Type.Float ["(123,456)"]) pUS5
|
||||
|
||||
Test.specify "should correctly parse decimals in European formats" <|
|
||||
cDE = Column.from_vector "floats" ["1,23", "000123", "-1.234,567", "1.234.567,789", "12.34,56"]
|
||||
pDE = cDE.parse type=Value_Type.Float
|
||||
|
@ -525,12 +525,14 @@ spec =
|
||||
|
||||
Test.specify "should work happily with mixed types" <|
|
||||
c_0 = ['A', ["H", "B", "C"]]
|
||||
c_00 = ['AA', ["", "B", "C"]]
|
||||
c_1 = ['B', [Date.new 1980, Date.new 1979, Date.new 2000]]
|
||||
c_2 = ['x', [1, 2, 3]]
|
||||
c_3 = ['Y', [5.3, 56.2, 6.3]]
|
||||
c_4 = ['Z', [True, False, True]]
|
||||
table = Table.new [c_0, c_1, c_2, c_3, c_4]
|
||||
expect_column_names ["H", "1980-01-01", "1", "5.3", "True"] <| table.use_first_row_as_names
|
||||
c_5 = ['ZZ', [Nothing, False, True]]
|
||||
table = Table.new [c_0, c_00, c_1, c_2, c_3, c_4, c_5]
|
||||
expect_column_names ["H", "Column_1", "1980-01-01", "1", "5.3", "True", "Column_2"] table.use_first_row_as_names
|
||||
|
||||
Test.specify "should correctly handle problems: invalid names ''" <|
|
||||
c_0 = ['A', ["", "B", "C"]]
|
||||
|
@ -250,7 +250,7 @@ spec =
|
||||
vec = [[0, 0], [3, -5], [1, 2], [0, 1]]
|
||||
m1 = Map.from_vector vec
|
||||
m1.should_fail_with Illegal_Argument
|
||||
m1.catch.message . should_equal "`Map.from_vector` encountered duplicate key: 0 (Integer)"
|
||||
m1.catch.message . should_equal "`Map.from_vector` encountered duplicate key: 0"
|
||||
|
||||
m2 = Map.from_vector vec allow_duplicates=True
|
||||
Problems.assume_no_problems m2
|
||||
@ -304,7 +304,7 @@ spec =
|
||||
m = Map.from_vector [[1, 2], [11, 3]]
|
||||
m2 = m.transform (k -> v -> [k % 10, v*2])
|
||||
m2.should_fail_with Illegal_Argument
|
||||
m2.catch.message . should_equal "`Map.transform` encountered duplicate key: 1 (Integer)"
|
||||
m2.catch.message . should_equal "`Map.transform` encountered duplicate key: 1"
|
||||
|
||||
Test.specify "should allow mapping over values" <|
|
||||
m = Map.empty . insert 1 2 . insert 2 4
|
||||
|
@ -1,18 +1,12 @@
|
||||
from Standard.Base import all
|
||||
import Standard.Base.Errors.Unimplemented.Unimplemented
|
||||
|
||||
import Standard.Base.Data.Noise.Generator
|
||||
import Standard.Base.Data.Noise.Deterministic_Random
|
||||
|
||||
from Standard.Test import Test, Test_Suite
|
||||
import Standard.Test.Extensions
|
||||
|
||||
spec =
|
||||
Test.group "Generator Interface" <|
|
||||
gen = Generator
|
||||
Test.specify "should not be invokable" <|
|
||||
interval = Interval.inclusive 0 1
|
||||
Test.expect_panic_with (gen.step 1 interval) Unimplemented
|
||||
Test.group "Deterministic Random Noise Generator" <|
|
||||
gen = Deterministic_Random
|
||||
Test.specify "should always return the same output for the same input" <|
|
||||
|
@ -98,18 +98,18 @@ spec =
|
||||
disp = long.to_display_text
|
||||
disp.length . should_equal 80
|
||||
disp.characters.take (First 5) . should_equal [ 'H', 'e', 'l', 'l', 'o' ]
|
||||
disp.characters.take (Last 6) . should_equal ['l', 'd', '!', ' ', 'H', 'e']
|
||||
disp.characters.take (Last 6) . should_equal ['l', 'd', '!', ' ', ' ', '…']
|
||||
|
||||
Test.specify "grapheme 1 conversion" <|
|
||||
txt = 'a\u0321\u0302'*100
|
||||
txt.to_display_text . should_equal 'a\u0321\u0302'*80
|
||||
txt.to_display_text . should_equal ('a\u0321\u0302'*78 + ' …')
|
||||
|
||||
Test.specify "grapheme 2 conversion" <|
|
||||
txt = '\u0915\u094D\u0937\u093F'*100
|
||||
txt.to_display_text . should_equal '\u0915\u094D\u0937\u093F'*80
|
||||
txt.to_display_text . should_equal ('\u0915\u094D\u0937\u093F'*78 + ' …')
|
||||
|
||||
Test.specify "grapheme 3 conversion" <|
|
||||
txt = '\u{1F926}\u{1F3FC}\u200D\u2642\uFE0F'*100
|
||||
txt.to_display_text . should_equal '\u{1F926}\u{1F3FC}\u200D\u2642\uFE0F'*80
|
||||
txt.to_display_text . should_equal ('\u{1F926}\u{1F3FC}\u200D\u2642\uFE0F'*78 + ' …')
|
||||
|
||||
main = Test_Suite.run_main spec
|
||||
|
@ -142,6 +142,7 @@ spec_with name create_new_datetime parse_datetime nanoseconds_loss_in_precision=
|
||||
time . second . should_equal 1
|
||||
time . nanosecond . should_equal 0
|
||||
time . zone . zone_id . should_equal "Europe/Paris"
|
||||
time.to_display_text . should_equal "1970-01-01 00:00:01 Europe/Paris"
|
||||
|
||||
Test.specify "should throw error when parsing invalid time" <|
|
||||
case parse_datetime "2008-1-1" . catch of
|
||||
@ -199,6 +200,7 @@ spec_with name create_new_datetime parse_datetime nanoseconds_loss_in_precision=
|
||||
time . second . should_equal 1
|
||||
time . nanosecond . should_equal 0
|
||||
time . zone . zone_id . should_equal tz.zone_id
|
||||
time.to_display_text . should_equal "1970-01-01 01:01:01 +01:01:01"
|
||||
|
||||
Test.specify "should set id-based timezone" <|
|
||||
tz = Time_Zone.parse "Europe/Moscow"
|
||||
@ -211,6 +213,7 @@ spec_with name create_new_datetime parse_datetime nanoseconds_loss_in_precision=
|
||||
time . second . should_equal 0
|
||||
time . nanosecond . should_equal 0
|
||||
time . zone . zone_id . should_equal tz.zone_id
|
||||
time.to_display_text . should_equal "1970-01-01 03:00:00 Europe/Moscow"
|
||||
|
||||
Test.specify "should get time of day from offsed-based time" <|
|
||||
time = parse_datetime "1970-01-01T00:00:01+01:00" . time_of_day
|
||||
|
@ -34,6 +34,15 @@ spec =
|
||||
duration = (Duration.new hours=13) - (Duration.new hours=1)
|
||||
duration.hours . should_equal 12
|
||||
|
||||
Test.specify "should render a friendly to display text" <|
|
||||
Duration.new . to_display_text . should_equal "0s"
|
||||
Duration.new seconds=30 . to_display_text . should_equal "30s"
|
||||
Duration.new seconds=30 milliseconds=500 . to_display_text . should_equal "30.5s"
|
||||
Duration.new hours=1 . to_display_text . should_equal "1h"
|
||||
Duration.new hours=1 minutes=30 . to_display_text . should_equal "1h 30m"
|
||||
Duration.new hours=1 seconds=30 . to_display_text . should_equal "1h 0m 30s"
|
||||
Duration.new hours=1 minutes=30 seconds=30 . to_display_text . should_equal "1h 30m 30s"
|
||||
|
||||
Test.specify "should convert to Json" <|
|
||||
interval = (Duration.new nanoseconds=120) + (Duration.new seconds=30) + (Duration.new hours=14)
|
||||
interval.to_json.should_equal <|
|
||||
|
@ -41,4 +41,13 @@ spec =
|
||||
((Period.new years=1 days=10) == (Period.new years=1 days=10)) . should_be_true
|
||||
((Period.new days=1) != (Period.new months=1)) . should_be_true
|
||||
|
||||
Test.specify "should render a friendly to display text" <|
|
||||
Period.new . to_display_text . should_equal "0D"
|
||||
Period.new years=2 . to_display_text . should_equal "2Y"
|
||||
Period.new months=24 . to_display_text . should_equal "2Y"
|
||||
Period.new months=4 . to_display_text . should_equal "4M"
|
||||
Period.new months=18 . to_display_text . should_equal "1Y 6M"
|
||||
Period.new years=2 days=3 . to_display_text . should_equal "2Y 0M 3D"
|
||||
Period.new days=18 . to_display_text . should_equal "18D"
|
||||
|
||||
main = Test_Suite.run_main spec
|
||||
|
@ -31,14 +31,14 @@ visualization_spec connection =
|
||||
p_all_rows = ["all_rows_count", all_rows]
|
||||
p_ixes = ["indices", ixes]
|
||||
p_ixes_header = ["indices_header", ixes_header]
|
||||
pairs = [p_header, p_data, p_all_rows, p_ixes, p_ixes_header]
|
||||
pairs = [p_header, p_data, p_all_rows, p_ixes, p_ixes_header, ["type", "Table"]]
|
||||
JS_Object.from_pairs pairs . to_text
|
||||
|
||||
Test.group "Table Visualization" <|
|
||||
Test.specify "should wrap internal errors" <|
|
||||
bad_table = Database_Table.Value Nothing Nothing Nothing Nothing
|
||||
vis = Visualization.prepare_visualization bad_table 2
|
||||
json = JS_Object.from_pairs [["error", "Method `set_limit` of Nothing could not be found."]]
|
||||
json = JS_Object.from_pairs [["error", "Method `set_limit` of type Nothing could not be found."]]
|
||||
vis . should_equal json.to_text
|
||||
|
||||
Test.specify "should visualize database tables" <|
|
||||
@ -69,30 +69,34 @@ visualization_spec connection =
|
||||
|
||||
Test.specify "should handle Vectors" <|
|
||||
vis = Visualization.prepare_visualization [1, 2, 3] 2
|
||||
json = JS_Object.from_pairs [["json", [1, 2]], ["all_rows_count", 3]]
|
||||
json = JS_Object.from_pairs [["type", "Vector"], ["all_rows_count", 3], ["json", [1, 2]]]
|
||||
vis . should_equal json.to_text
|
||||
|
||||
vis2 = Visualization.prepare_visualization [[1, 2], [3, 4]] 2
|
||||
json2 = JS_Object.from_pairs [["json", [[1, 2], [3, 4]]], ["all_rows_count", 2]]
|
||||
json2 = JS_Object.from_pairs [["type", "Matrix"], ["all_rows_count", 2], ["json", [[1, 2], [3, 4]]], ["column_count", 2]]
|
||||
vis2 . should_equal json2.to_text
|
||||
|
||||
Test.specify "should handle Arrays" <|
|
||||
vis = Visualization.prepare_visualization ([1, 2, 3] . to_array) 2
|
||||
json = JS_Object.from_pairs [["json", [1, 2]], ["all_rows_count", 3]]
|
||||
json = JS_Object.from_pairs [["type", "Vector"], ["all_rows_count", 3], ["json", [1, 2]]]
|
||||
vis . should_equal json.to_text
|
||||
|
||||
Test.specify "should handle other datatypes" <|
|
||||
vis = Visualization.prepare_visualization (Foo.Value 42) 2
|
||||
json = JS_Object.from_pairs [["json", (Foo.Value 42)]]
|
||||
json = JS_Object.from_pairs [["json", JS_Object.from_pairs [["_display_text_", (Foo.Value 42).to_display_text],["x", 42]]]]
|
||||
vis . should_equal json.to_text
|
||||
|
||||
Test.specify "should visualize value type info" <|
|
||||
Value_Type.Boolean.to_json . should_equal '{"type":"Value_Type","constructor":"Boolean","_display_text_":"Boolean"}'
|
||||
Value_Type.Float.to_json . should_equal '{"type":"Value_Type","constructor":"Float","_display_text_":"Float (64 bits)","bits":64}'
|
||||
Value_Type.Decimal.to_json . should_equal '{"type":"Value_Type","constructor":"Decimal","_display_text_":"Decimal (precision=Nothing, scale=Nothing)","precision":null,"scale":null}'
|
||||
Value_Type.Char.to_json . should_equal '{"type":"Value_Type","constructor":"Char","_display_text_":"Char (max_size=Nothing, variable_length=True)","size":null,"variable_length":true}'
|
||||
Value_Type.Unsupported_Data_Type.to_json . should_equal '{"type":"Value_Type","constructor":"Unsupported_Data_Type","_display_text_":"Unsupported_Data_Type","type_name":null}'
|
||||
make_json vt =
|
||||
js_object = vt.to_js_object
|
||||
pairs = [["_display_text_", vt.to_display_text]] + vt.to_js_object.field_names.map f-> [f, js_object.get f]
|
||||
JS_Object.from_pairs [["json", JS_Object.from_pairs pairs]] . to_text
|
||||
|
||||
Visualization.prepare_visualization Value_Type.Boolean . should_equal (make_json Value_Type.Boolean)
|
||||
Visualization.prepare_visualization Value_Type.Float . should_equal (make_json Value_Type.Float)
|
||||
Visualization.prepare_visualization Value_Type.Decimal . should_equal (make_json Value_Type.Decimal)
|
||||
Visualization.prepare_visualization Value_Type.Char . should_equal (make_json Value_Type.Char)
|
||||
Visualization.prepare_visualization Value_Type.Unsupported_Data_Type . should_equal (make_json Value_Type.Unsupported_Data_Type)
|
||||
|
||||
spec =
|
||||
enso_project.data.create_directory
|
||||
|
@ -1,6 +1,6 @@
|
||||
import project.Meta
|
||||
import project.Error.Error
|
||||
import project.Any.Any
|
||||
import project.Error.Error
|
||||
import project.Meta
|
||||
|
||||
|
||||
@Builtin_Type
|
||||
@ -50,7 +50,9 @@ type No_Such_Method
|
||||
|
||||
method_name self = Meta.meta self.symbol . name
|
||||
|
||||
to_display_text self = "Method `"+self.method_name+"` of "+self.target.to_display_text+" could not be found."
|
||||
to_display_text self =
|
||||
target_type_name = if Meta.is_polyglot self.target then self.target.to_display_text else (Meta.type_of self.target).to_display_text
|
||||
"Method `"+self.method_name+"` of type "+target_type_name+" could not be found."
|
||||
|
||||
@Builtin_Type
|
||||
type Module_Not_In_Package_Error
|
||||
|
@ -10,6 +10,8 @@ type Primitive
|
||||
|
||||
type_of value = @Builtin_Method "Meta.type_of"
|
||||
|
||||
is_polyglot value = @Builtin_Method "Meta.is_polyglot"
|
||||
|
||||
# A **very** minimal version of meta for the purpose of tests
|
||||
meta value =
|
||||
if is_unresolved_symbol value then Unresolved_Symbol.Value value else
|
||||
|
Loading…
Reference in New Issue
Block a user