feat(#3251): added text and sscanf to eo-runtime

This commit is contained in:
maxonfjvipon 2024-07-17 17:03:29 +03:00
parent 0927a50ebf
commit b248cfd4af
No known key found for this signature in database
GPG Key ID: D8563899D473D273
14 changed files with 1251 additions and 270 deletions

View File

@ -25,7 +25,4 @@
# package name contains capital letter and such names are conventional.
---
exclude_paths:
- "eo-runtime/src/test/java/EOorg/EOeolang/EOtxt/EOsprintfTest.java"
- "eo-runtime/src/test/java/EOorg/EOeolang/EOtxt/package-info.java"
- "eo-runtime/src/main/java/EOorg/EOeolang/EOtxt/EOsprintf.java"
- "eo-runtime/src/main/java/EOorg/EOeolang/EOtxt/package-info.java"
- "eo-runtime/src/main/java/EOorg/EOeolang/EOtxt/EOsscanf.java"

View File

@ -32,12 +32,6 @@
[as-bytes] > string
as-bytes > @
# Is true if both objects are equal.
[x] > eq
eq. > @
^.as-bytes
x.as-bytes
# Get the length of it.
[] > length /int

View File

@ -0,0 +1,35 @@
# The MIT License (MIT)
#
# Copyright (c) 2016-2024 Objectionary.com
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
+architect yegor256@gmail.com
+home https://github.com/objectionary/eo
+package org.eolang.txt
+rt jvm org.eolang:eo-runtime:0.0.0
+rt node eo2js-runtime:0.0.0
+version 0.0.0
# Reads formatted input from a string.
# This object has two free attributes:
# 1. `format` - is a formatter string (e.g. "Hello, %s!")
# 2. `read` - is a string where data exists (e.g. "Hello, John!")
# returns a `tuple` of formatted values (e.g. * "John").
[format read] > sscanf /tuple

View File

@ -0,0 +1,452 @@
# The MIT License (MIT)
#
# Copyright (c) 2016-2024 Objectionary.com
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
+alias org.eolang.structs.list
+alias org.eolang.structs.bytes-as-array
+alias org.eolang.txt.sprintf
+alias org.eolang.txt.sscanf
+architect yegor256@gmail.com
+home https://github.com/objectionary/eo
+package org.eolang.txt
+rt jvm org.eolang:eo-runtime:0.0.0
+rt node eo2js-runtime:0.0.0
+version 0.0.0
# Text.
[origin] > text
origin > @
# Takes a piece of a `text` as another `text`.
# Here `start` must be an integer index to start slicing from,
# `len` must be an integer which shows how much symbols should be sliced.
[start len] > slice
text > @
^.origin.slice start len
# Returns `text` trimmed from left side.
[] > trimmed-left
^.origin.length > len!
if. > @
0.eq len
^
^.slice
first-non-space-index 0 > idx!
(int len).minus (int idx)
[index] > first-non-space-index
^.^.origin.slice index 1 > char!
if. > @
^.len.eq index
index
if.
" ".eq char
^.first-non-space-index
index.plus 1
index
# Returns `text` trimmed from right side.
[] > trimmed-right
^.origin.length > len!
if. > @
0.eq len
^
^.slice
0
first-non-space-index
(int len).plus -1
[index] > first-non-space-index
^.^.origin.slice index 1 > char!
if. > @
-1.eq index
0
if.
" ".eq char
^.first-non-space-index
index.plus -1
index.plus 1
# Returns `text` trimmed from both sides.
[] > trimmed
if. > @
0.eq ^.length
^
trimmed-right.
trimmed-left.
^
# Joins `items`, which is a `tuple` of strings, using current `string`
# as a delimiter.
[items] > joined
^.origin > delimiter!
items.length > len!
text > @
if.
0.eq len
""
if.
1.eq len
items.at 0 > first
as-string.
concat.
first.as-bytes
with-delimiter "".as-bytes 1
[acc index] > with-delimiter
if. > @
^.len.eq index
acc
^.with-delimiter
acc.concat
^.delimiter.concat
^.items.at index
index.plus 1
# Returns `text` repeated `times` times.
# If `times` < 0 - an error is returned.
# If `times` == 0 - an original text is returned.
[times] > repeated
^.origin.as-bytes > bts!
if. > @
0.gt
times > amount!
error
sprintf
"Can't repeat text %d times"
* amount
text
if.
0.eq amount
""
as-string.
rec-repeated bts 1
[accum index] > rec-repeated
if. > @
^.amount.eq index
accum
^.rec-repeated
accum.concat ^.bts
index.plus 1
# Checks if current `text` contains given `substring`.
[substring] > contains
not. > @
eq.
-1
^.index-of substring
# Checks that current `text` ends with given `substring`.
[substring] > ends-with
eq. > @
^.index-of
substring > substr!
^.length.minus substr.size
# Checks that current `text` starts with given `substring`.
[substring] > starts-with
eq. > @
0
^.index-of substring
# Returns index of `substring` in current `text`.
# If no `substring` was found, it returns -1
[substring] > index-of
^.origin.length > self-len!
size. > sub-len!
substring > substr!
(int self-len).minus (int sub-len) > end!
if. > @
or.
(int sub-len).gt self-len
and.
sub-len.eq self-len
(substr.eq ^.origin).not
-1
rec-index-of-substr 0
[idx] > rec-index-of-substr
if. > @
^.end.eq idx
if.
eq. > contains
^.substr
^.^.slice idx ^.sub-len
idx
-1
if.
contains
idx
^.rec-index-of-substr
idx.plus 1
# Returns last index of `substring` in current `text`.
# If no element was found, it returns -1.
[substring] > last-index-of
^.origin.length > self-len!
size. > sub-len!
substring > substr!
if. > @
or.
(int sub-len).gt self-len
and.
sub-len.eq self-len
(substr.eq ^.origin).not
-1
rec-index-of-substr
(int self-len).minus (int sub-len)
[idx] > rec-index-of-substr
if. > @
0.eq idx
if.
eq. > contains
^.substr
^.^.slice idx ^.sub-len
idx
-1
if.
contains
idx
^.rec-index-of-substr
idx.plus -1
# Returns `text` in upper case.
[] > up-cased
ascii "z" > ascii-z!
minus. > distance
int
ascii "a" > ascii-a!
ascii "A"
text > @
as-string.
reduced.
list
bytes-as-array
^.origin.as-bytes
--
[accum byte] >>
^.ascii byte > ascii-bte
accum.concat > @
if.
and.
ascii-bte.lte ^.ascii-z
ascii-bte.gte ^.ascii-a
slice.
as-bytes.
ascii-bte.minus ^.distance
7
1
byte
[char] > ascii
as-int. > @
concat.
00-00-00-00-00-00-00
char.as-bytes
# Returns `text` in lower case.
[] > low-cased
^.up-cased.ascii "Z" > ascii-z
^.up-cased.ascii "A" > ascii-a
text > @
as-string.
reduced.
list
bytes-as-array
^.origin.as-bytes
--
[accum byte] >>
^.^.up-cased.ascii byte > ascii-bte
accum.concat > @
if.
and.
ascii-bte.lte ^.ascii-z
ascii-bte.gte ^.ascii-a
slice.
as-bytes.
ascii-bte.plus ^.^.up-cased.distance
7
1
byte
# Retrieve symbol by given index as `text`.
# If 0 > index >= ^.length - the error will be returned.
[i] > at
^.length > len!
if. > index!
0.gt
i > idx!
(int len).plus idx
idx
if. > @
or.
0.gt index
(int index).gte len
error
sprintf
"Given index %d is out of text bounds"
* index
^.slice index 1
# Returns text where all regexp
# target changed to replacement.
# @todo #3251:30min Implement text.replaced object. This object was an atom in
# eo-strings. Maybe there's a way to implement it in pure EO. Don't remember to
# write some tests when object is implemented.
^ > [target replacement] > replaced
# Returns the original `text` as `int`.
[] > as-int
if. > @
eq.
0
length.
sscanf "%d" ^.origin > scanned
error
sprintf
"Can't convert text %s to int"
* ^.origin
scanned.tail
# Returns the original `text` as `float`.
[] > as-float
if. > @
eq.
0
length.
sscanf "%f" ^.origin > scanned
error
sprintf
"Can't convert text %s to float"
* ^.origin
scanned.tail
# Returns a `list` of `strings`, separated by a given `delimiter`.
[delimiter] > split
delimiter > delim!
^.origin.as-bytes > self-as-bytes
self-as-bytes.size > len!
list > @
if.
len.eq 0
*
rec-split * 0 0
[accum start current] > rec-split
if. > @
^.len.eq current
accum.with > with-substr
^.self-as-bytes.slice
start
current.minus start
if.
eq.
^.delim
^.self-as-bytes.slice current 1
^.rec-split
with-substr
current.plus 1
current.plus 1
^.rec-split
accum
start
current.plus 1
# Check that all signs in string are numbers or letters.
# Works only for english letters
[] > is-alphabetic
reduced. > @
list
bytes-as-array
^.low-cased.as-bytes
true
[accum byte] >>
and. > @
accum
^.int-is-alphabetic
concat.
00-00-00-00-00-00-00
byte
[bte] > int-is-alphabetic
or. > @
and.
48.lte bte
57.gte bte
and.
97.lte bte
122.gte bte
# Check that all signs in string are letters.
# Works only for english letters.
[] > is-alpha
reduced. > @
list
bytes-as-array
^.low-cased.as-bytes
true
[accum byte] >>
and. > @
accum
^.int-is-alpha
concat.
00-00-00-00-00-00-00
byte
[bte] > int-is-alpha
and. > @
97.lte bte
122.gte bte
# Check that all signs in string are ASCII characters.
[] > is-ascii
reduced. > @
list
bytes-as-array
^.origin.as-bytes
true
[accum byte] >>
and. > @
accum
^.int-is-ascii
concat.
00-00-00-00-00-00-00
byte
[bte] > int-is-ascii
and. > @
0.lte bte
127.gte bte
# Returns concatenation of all `other` strings.
# Here `other` must be a `tuple` of `strings`.
[others] > chained
if. > @
0.eq others.length
^
text
as-string.
reduced.
list others
^.origin.as-bytes
accum.concat str.as-bytes > [accum str]

View File

@ -1,54 +0,0 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2016-2024 Objectionary.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* @checkstyle PackageNameCheck (4 lines)
*/
package EOorg.EOeolang;
import java.nio.charset.StandardCharsets;
import org.eolang.Atom;
import org.eolang.Data;
import org.eolang.Param;
import org.eolang.PhDefault;
import org.eolang.Phi;
import org.eolang.Versionized;
import org.eolang.XmirObject;
/**
* AS-BYTES.
*
* @since 1.0
* @checkstyle TypeNameCheck (5 lines)
*/
@Versionized
@XmirObject(oname = "string.as-bytes")
public final class EOstring$EOas_bytes extends PhDefault implements Atom {
@Override
public Phi lambda() {
return new Data.ToPhi(
new Param(this).strong(String.class).getBytes(StandardCharsets.UTF_8)
);
}
}

View File

@ -28,9 +28,12 @@
package EOorg.EOeolang.EOtxt;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.StringJoiner;
import java.util.function.Function;
import org.eolang.AtVoid;
import org.eolang.Atom;
import org.eolang.Data;
@ -43,12 +46,29 @@ import org.eolang.XmirObject;
/**
* Sprintf.
*
* @since 0.39.0
* @checkstyle TypeNameCheck (5 lines)
*/
@XmirObject(oname = "sprintf")
public final class EOsprintf extends PhDefault implements Atom {
/**
* Character conversion.
* @checkstyle IndentationCheck (15 lines)
*/
private static final Map<Character, Function<Dataized, Object>> CONVERSION =
new HashMap<Character, Function<Dataized, Object>>(5) {{
put('s', element -> element.take(String.class));
put('d', element -> element.take(Long.class));
put('f', element -> element.take(Double.class));
put('x', element -> EOsprintf.bytesToHex(element.take()));
put('b', element -> element.take(Boolean.class));
}};
/**
* Percent sign.
*/
private static final char PERCENT = '%';
/**
* Ctor.
*/
@ -67,7 +87,7 @@ public final class EOsprintf extends PhDefault implements Atom {
String pattern = format;
long index = 0;
while (true) {
final int idx = pattern.indexOf('%');
final int idx = pattern.indexOf(EOsprintf.PERCENT);
if (idx == -1) {
break;
}
@ -76,16 +96,20 @@ public final class EOsprintf extends PhDefault implements Atom {
String.format(
"The amount of arguments %d does not match the amount of format occurrences %d",
length,
EOsprintf.percents(format)
EOsprintf.formats(format)
)
);
}
final char sym = pattern.charAt(idx + 1);
final Phi taken = retriever.copy();
taken.put(0, new Data.ToPhi(index));
arguments.add(EOsprintf.formatted(sym, new Dataized(taken)));
pattern = pattern.substring(idx + 1);
++index;
if (sym != EOsprintf.PERCENT) {
final Phi taken = retriever.copy();
taken.put(0, new Data.ToPhi(index));
arguments.add(EOsprintf.formatted(sym, new Dataized(taken)));
++index;
pattern = pattern.substring(idx + 2);
} else {
pattern = pattern.substring(idx + 1);
}
}
return new ToPhi(
String.format(
@ -116,44 +140,30 @@ public final class EOsprintf extends PhDefault implements Atom {
* @return Formatted object
*/
private static Object formatted(final char symbol, final Dataized element) {
final Object result;
switch (symbol) {
case 's':
result = element.take(String.class);
break;
case 'd':
result = element.take(Long.class);
break;
case 'f':
result = element.take(Double.class);
break;
case 'x':
result = EOsprintf.bytesToHex(element.take());
break;
case 'b':
result = element.take(Boolean.class);
break;
default:
throw new ExFailure(
String.format(
"The format %c is unsupported, only %s formats can be used",
symbol,
"%s, %d, %f, %x, %b"
)
);
if (!EOsprintf.CONVERSION.containsKey(symbol)) {
throw new ExFailure(
String.format(
"The format %c is unsupported, only %s formats can be used",
symbol, "%s, %d, %f, %x, %b"
)
);
}
return result;
return EOsprintf.CONVERSION.get(symbol).apply(element);
}
/**
* Count amount of '%' char occurrences.
* Count amount of format occurrences.
* @param str Given string
* @return Amount of '%' in string
* @return Amount of formats in string
*/
private static int percents(final String str) {
private static int formats(final String str) {
int count = 0;
for (int idx = 0; idx < str.length(); ++idx) {
if (str.charAt(idx) == '%') {
if (
str.charAt(idx) == EOsprintf.PERCENT
&& idx + 1 != str.length()
&& EOsprintf.CONVERSION.containsKey(str.charAt(idx + 1))
) {
++count;
}
}

View File

@ -0,0 +1,154 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2016-2024 Objectionary.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* @checkstyle PackageNameCheck (4 lines)
*/
package EOorg.EOeolang.EOtxt;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eolang.AtVoid;
import org.eolang.Atom;
import org.eolang.Data;
import org.eolang.ExFailure;
import org.eolang.Param;
import org.eolang.PhDefault;
import org.eolang.Phi;
import org.eolang.XmirObject;
/**
* Sscanf.
* @since 0.39
* @checkstyle TypeNameCheck (5 lines)
*/
@XmirObject(oname = "sscanf")
public final class EOsscanf extends PhDefault implements Atom {
/**
* Character conversion.
* @checkstyle IndentationCheck (10 lines)
*/
private static final Map<Character, Function<String, Phi>> CONVERSION =
new HashMap<Character, Function<String, Phi>>(3) {{
put('s', ToPhi::new);
put('d', str -> new Data.ToPhi(Long.parseLong(str)));
put('f', str -> new Data.ToPhi(Double.parseDouble(str)));
}};
/**
* Percent sign.
*/
private static final char PERCENT = '%';
/**
* Ctor.
* @checkstyle CyclomaticComplexityCheck (75 lines)
* @checkstyle NestedIfDepthCheck (75 lines)
*/
public EOsscanf() {
this.add("format", new AtVoid("format"));
this.add("read", new AtVoid("read"));
}
@Override
public Phi lambda() throws Exception {
final String format = new Param(this, "format").strong(String.class);
final List<Phi> output = new ArrayList<>(0);
final StringBuilder regex = new StringBuilder();
boolean literal = false;
for (int idx = 0; idx < format.length(); ++idx) {
final char sym = format.charAt(idx);
if (sym == EOsscanf.PERCENT) {
if (literal) {
regex.append(EOsscanf.PERCENT);
literal = false;
} else {
literal = true;
}
} else {
if (literal) {
switch (sym) {
case 'd':
regex.append("(\\d+)");
break;
case 'f':
regex.append("([+-]?\\d*\\.\\d+)");
break;
case 's':
regex.append("(\\S+)");
break;
default:
throw new ExFailure("Unsupported format specifier: '%%%c'", sym);
}
literal = false;
} else {
regex.append(Pattern.quote(String.valueOf(sym)));
}
}
}
final Matcher matcher = Pattern.compile(regex.toString()).matcher(
new Param(this, "read").strong(String.class)
);
String frmt = format;
if (matcher.find()) {
int index = 1;
while (true) {
final int idx = frmt.indexOf(EOsscanf.PERCENT);
if (idx == -1) {
break;
}
final char sym = frmt.charAt(idx + 1);
if (sym != EOsscanf.PERCENT) {
output.add(EOsscanf.converted(sym, matcher.group(index)));
++index;
}
frmt = frmt.substring(idx + 2);
}
}
return new Data.ToPhi(output.toArray(new Phi[0]));
}
/**
* Convert given string to {@link Phi} depending on format {@code symbol}.
* @param symbol Format symbol
* @param str String to format
* @return Phi object depending on format symbol
*/
private static Phi converted(final char symbol, final String str) {
if (!EOsscanf.CONVERSION.containsKey(symbol)) {
throw new ExFailure(
String.format(
"The format %c is unsupported, only %s formats can be used",
symbol, "%s, %d, %f"
)
);
}
return EOsscanf.CONVERSION.get(symbol).apply(str);
}
}

View File

@ -20,6 +20,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
+alias org.eolang.io.stdout
+alias org.eolang.txt.sprintf
+architect yegor256@gmail.com
+home https://github.com/objectionary/eo
@ -50,3 +51,43 @@
sprintf
"%x"
* 42.as-bytes
# Test.
[] > formats-all-objects
eq. > @
"string Jeff, bytes 4A-65-66-66, float 42.300000, int 14, bool false"
sprintf
"string %s, bytes %x, float %f, int %d, bool %b"
* "Jeff" "Jeff".as-bytes 42.3 14 false
# Test.
[] > sprintf-fails-if-amount-of-arguments-does-not-match
try > @
sprintf
"%s%s"
* "Jeff"
stdout ex > [ex]
false
# Test.
[] > sprintf-does-not-fail-if-arguments-more-than-formats
eq. > @
"Hey"
sprintf
"%s"
* "Hey" "Jeff"
# Test.
[] > fails-on-unsupported-format
try > @
sprintf "%o" *
stdout ex > [ex]
false
# Test.
[] > sprintf-prints-percents
eq. > @
"%Jeff"
sprintf
"%%%s"
* "Jeff"

View File

@ -0,0 +1,121 @@
# The MIT License (MIT)
#
# Copyright (c) 2016-2024 Objectionary.com
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
+alias org.eolang.io.stdout
+alias org.eolang.txt.sprintf
+alias org.eolang.txt.sscanf
+alias org.eolang.structs.list
+architect yegor256@gmail.com
+home https://github.com/objectionary/eo
+tests
+package org.eolang.txt
+version 0.0.0
# Test.
[] > sscanf-with-string
eq. > @
"hello"
tail.
sscanf "%s" "hello"
# Test.
[] > sscanf-with-int
eq. > @
33
tail.
sscanf "%d" "33"
# Test.
[] > sscanf-with-float
eq. > @
0.24
tail.
sscanf "%f" "0.24"
# Test.
[] > sscanf-with-error
try > @
sscanf "%l" "error"
stdout ex > [ex]
false
# Test.
[] > sscanf-with-string-int-float
eq. > @
list
sscanf
"%s %d %f"
"hello 33 0.24"
* "hello" 33 0.24
# Test.
[] > sscanf-with-string-with-ending
eq. > @
"hello"
tail.
sscanf "%s!" "hello!"
# Test.
[] > sscanf-with-complex-string
eq. > @
"test"
tail.
sscanf "some%sstring" "someteststring"
# Test.
[] > sscanf-with-complex-int
eq. > @
734987259
tail.
sscanf "!%d!" "!734987259!"
# Test.
[] > sscanf-with-complex-float
eq. > @
1991.01
tail.
sscanf "this will be=%f" "this will be=1991.01"
# Test.
[] > sscanf-with-sprintf
eq. > @
list
sscanf
"%s is about %d?"
sprintf
"%s is about %d?"
* "This" 8
* "This" 8
# Test.
[] > sscanf-complex-case
eq. > @
list
sscanf
"Im%d %s old and this is! Let's calculate %f + %f= %f"
"Im18 years old and this is! Let's calculate 99999999.99 + 0.01= 100000000.0"
*
18
"years"
99999999.99
0.01
100000000.0

View File

@ -0,0 +1,391 @@
# The MIT License (MIT)
#
# Copyright (c) 2016-2024 Objectionary.com
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
+alias org.eolang.txt.text
+alias org.eolang.io.stdout
+architect yegor256@gmail.com
+home https://github.com/objectionary/eo
+tests
+package org.eolang.txt
+version 0.0.0
# Test.
[] > text-slices-the-origin-string
eq. > @
(text "Hello, world!").slice 7 5
"world"
# Test.
[] > trimmed-left-empty-text
eq. > @
(text "").trimmed-left
""
# Test.
[] > text-trimmed-left-one-space
eq. > @
(text " s").trimmed-left
"s"
# Test.
[] > text-trimmed-left-many-spaces
eq. > @
(text " some").trimmed-left
"some"
# Test.
[] > text-trimmed-left-only-spaces
eq. > @
(text " ").trimmed-left
""
# Test.
[] > trimmed-right-empty-text
eq. > @
(text "").trimmed-right
""
# Test.
[] > text-trimmed-right-one-space
eq. > @
(text "s ").trimmed-right
"s"
# Test.
[] > text-trimmed-right-many-spaces
eq. > @
(text "some ").trimmed-right
"some"
# Test.
[] > text-trimmed-right-only-spaces
eq. > @
(text " ").trimmed-right
""
# Test.
[] > text-trimmed-one-space-left
eq. > @
(text " some").trimmed
"some"
# Test.
[] > text-trimmed-one-space-right
eq. > @
(text "some ").trimmed
"some"
# Test.
[] > text-trimmed-one-space-both
eq. > @
(text " some ").trimmed
"some"
# Test.
[] > text-trimmed-many-spaces
eq. > @
(text " some ").trimmed
"some"
# Test.
[] > text-trimmed-empty
eq. > @
(text "").trimmed
""
# Test.
[] > text-trimmed-only-spaces
eq. > @
(text " ").trimmed
""
# Test.
[] > returns-first-char
eq. > @
"s"
(text "some").at 0
# Test.
[] > returns-third-char
eq. > @
"m"
(text "some").at 2
# Test.
[] > returns-char-at-negative-index
eq. > @
"m"
(text "some").at -2
# Test.
[] > returns-error-at-index-more-than-length
try > @
(text "some").at 10
stdout ex > [ex]
false
# Test.
[] > chains-with-other-strings
eq. > @
"Hello, world!"
chained.
text "Hello"
*
", "
"world"
"!"
# Test.
[] > returns-same-text-on-chaining-with-no-strings
eq. > @
"Some"
chained.
text "Some"
*
# Test.
[] > joined-no-strings
eq. > @
""
(text "-").joined *
# Test.
[] > joined-one-string
eq. > @
"some"
(text "-").joined
* "some"
# Test.
[] > joined-many-strings
eq. > @
"hello-world-dear-friend"
(text "-").joined
* "hello" "world" "dear" "friend"
# Test.
[] > text-repeat-less-than-zero-times
try > @
(text "").repeated -1
stdout ex > [ex]
false
# Test.
[] > text-repeated-zero-times-is-empty
eq. > @
""
(text "some").repeated 0
# Test.
[] > text-repeated-five-times
eq. > @
"heyheyheyheyhey"
(text "hey").repeated 5
# Test.
[] > index-of-non-existed-substring-with-more-length
eq. > @
-1
(text "Hello").index-of "Somebody"
# Test.
[] > index-of-non-existed-substring-with-same-length
eq. > @
-1
(text "Hello").index-of "world"
# Test.
[] > returns-valid-index-of-substring
eq. > @
3
(text "Hello world").index-of "lo wo"
# Test.
[] > returns-valid-index-of-substring-in-the-end
eq. > @
6
(text "Hello world").index-of "world"
# Test.
[] > starts-with-substring
(text "Hello, world").starts-with "Hello" > @
# Test.
[] > does-not-start-with-substring
not. > @
(text "Hello, world").starts-with "world"
# Test.
[] > ends-with-substring
(text "Hello world!").ends-with "world!" > @
# Test.
[] > does-not-end-with-substring
not. > @
(text "Hello world!").ends-with "Hello"
# Test.
[] > text-contains-substring
(text "Hello, world!").contains "o, wo" > @
# Test.
[] > text-does-not-contain-substring
not. > @
(text "Hello, world!").contains "Hey"
# Test.
[] > finds-last-index-of-substring
eq. > @
5
(text "Hey, Hey, Hey").last-index-of "Hey,"
# Test.
[] > finds-last-index-of-the-same-string
eq. > @
0
(text "Hello").last-index-of "Hello"
# Test.
[] > last-index-of-non-existed-substring
eq. > @
-1
(text "Hello, world").last-index-of "somebody"
# Test.
[] > splits-text-by-dash
eq. > @
(text "a-b-c").split "-"
* "a" "b" "c"
# Test.
[] > splits-text-with-empty-strings
eq. > @
(text "-a-b-").split "-"
* "" "a" "b" ""
# Test.
[] > converts-text-to-upper-case
eq. > @
"HELLO"
(text "hello").up-cased
# Test.
[] > converts-text-with-upper-letters-to-upper-case
eq. > @
"HELLO"
(text "HeLlO").up-cased
# Test.
[] > converts-text-to-lower-case
eq. > @
"hello"
(text "HELLO").low-cased
# Test.
[] > converts-text-with-low-letters-to-lower-case
eq. > @
"hello"
(text "HeLlO").low-cased
# Test.
[] > converts-text-to-int
eq. > @
5
(text "5").as-int
# Test.
[] > fails-on-converting-text-to-int
try > @
(text "Hello").as-int
stdout ex > [ex]
false
# Test.
[] > converts-text-to-float
eq. > @
3.14
(text "3.14").as-float
# Test.
[] > fails-on-converting-text-to-float
try > @
(text "Hello").as-float
stdout ex > [ex]
false
# Test.
[] > checks-if-text-is-ascii
is-ascii. > @
text
"H311oW"
# Test.
[] > checks-if-emoji-is-not-ascii
not. > @
is-ascii.
text
"🌵"
# Test.
[] > checks-if-string-of-numbers-is-ascii
is-ascii. > @
text
"123"
# Test.
[] > checks-if-simple-text-is-alphabetic
is-alphabetic. > @
text
"eEo"
# Test.
[] > checks-if-text-with-number-is-alphabetic
is-alphabetic. > @
text
"ab3d"
# Test.
[] > checks-if-text-with-dashes-is-not-alphabetic
not. > @
is-alphabetic.
text
"-w-"
# Test.
[] > checks-if-simple-text-is-alpha
is-alpha. > @
text
"eEo"
# Test.
[] > checks-if-text-with-number-is-not-alpha
not. > @
is-alpha.
text
"ab3d"
# Test.
[] > checks-if-text-with-dashes-is-not-alpha
not. > @
is-alpha.
text
"-w-"

View File

@ -1,122 +0,0 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2016-2024 Objectionary.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* @checkstyle PackageNameCheck (10 lines)
*/
package EOorg.EOeolang.EOtxt;
import EOorg.EOeolang.EOerror;
import java.nio.charset.StandardCharsets;
import org.eolang.Data;
import org.eolang.Dataized;
import org.eolang.Phi;
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
/**
* Test case for {@link EOsprintf}.
*
* @since 0.39
* @checkstyle TypeNameCheck (4 lines)
*/
final class EOsprintfTest {
@Test
void returnsValidFormattedString() {
final Phi sprintf = new EOsprintf();
sprintf.put(0, new Data.ToPhi("string %s, bytes %x, float %f, int %d, bool %b"));
sprintf.put(
1,
new Data.ToPhi(
new Phi[] {
new Data.ToPhi("Jeff"),
new Data.ToPhi("Jeff".getBytes(StandardCharsets.UTF_8)),
new Data.ToPhi(42.3),
new Data.ToPhi(14L),
new Data.ToPhi(false),
}
)
);
MatcherAssert.assertThat(
"All types should be formatted successfully",
new Dataized(sprintf).take(String.class),
Matchers.equalTo(
"string Jeff, bytes 4A-65-66-66, float 42.300000, int 14, bool false"
)
);
}
@Test
void failsIfAmountOfArgumentsDoesNotMatch() {
final Phi sprintf = new EOsprintf();
sprintf.put(0, new Data.ToPhi("%s%s"));
sprintf.put(1, new Data.ToPhi(new Phi[] {new Data.ToPhi("Hey")}));
final Throwable exception = Assertions.assertThrows(
EOerror.ExError.class,
() -> new Dataized(sprintf).take(),
"Dataization of sprintf should fail if formats < arguments"
);
MatcherAssert.assertThat(
"The exception message should contain an info about arguments and format occurrences amount",
exception.getMessage(),
Matchers.containsString(
"The amount of arguments 1 does not match the amount of format occurrences 2"
)
);
}
@Test
void doesNotFailIfArgumentsMoreThanFormats() {
final Phi sprintf = new EOsprintf();
sprintf.put(0, new Data.ToPhi("%s"));
sprintf.put(
1,
new Data.ToPhi(
new Phi[] {
new Data.ToPhi("Hey"),
new Data.ToPhi("Hey"),
}
)
);
MatcherAssert.assertThat(
"The second argument should be ignored",
new Dataized(sprintf).take(String.class),
Matchers.equalTo("Hey")
);
}
@Test
void failsOnUnsupportedFormat() {
final Phi sprintf = new EOsprintf();
sprintf.put(0, new Data.ToPhi("%o"));
sprintf.put(1, Phi.Φ.take("org.eolang.tuple").take("empty"));
Assertions.assertThrows(
EOerror.ExError.class,
() -> new Dataized(sprintf).take(),
"Sprintf dataization should fail because of unsupported format %o"
);
}
}

View File

@ -1,34 +0,0 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2016-2024 Objectionary.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* @checkstyle PackageNameCheck (20 lines)
*/
/**
* EO-txt, tests.
*
* @since 0.39
*/
package EOorg.EOeolang.EOtxt;

View File

@ -58,11 +58,6 @@ import org.yaml.snakeyaml.Yaml;
* Then, when new {@code eo-runtime.jar} is
* released to Maven Central, you enable this test again.</p>
* @since 0.1
* @todo #2718:30min One snippets is disabled now, in
* the "src/test/resources/snippets/*.yaml". It needs
* "sprintf" object in objectionary (fibo.yaml).
* When "sprintf" is in objectionary again - we need to enable
* it (by removing the "skip" attribute from the YAML file).
*/
@ExtendWith(WeAreOnline.class)
@SuppressWarnings({"JTCOP.RuleAllTestsHaveProductionClass", "JTCOP.RuleNotContainsTestWord"})
@ -126,7 +121,7 @@ final class SnippetTestCase {
.set("arguments", map.get("args"));
f.exec("clean", "test");
final String log = f.log();
Logger.debug(this, log);
Logger.info(this, log);
MatcherAssert.assertThat(
String.format("'%s' printed something wrong", yml),
log,

View File

@ -20,14 +20,14 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
---
skip: true
file: org/eolang/snippets/fibo.eo
out:
- ".*8 is the 6th number.*"
file: org/eolang/snippets/fibo.eo
args: [ "org.eolang.snippets.fibo" ]
eo: |
+package org.eolang.snippets
+alias org.eolang.io.stdout
+alias org.eolang.txt.sprintf
+package org.eolang.snippets
# This is the default 64+ symbols comment in front of named abstract object.
[args] > fibo
@ -40,7 +40,8 @@ eo: |
f (n.minus 1)
f (n.minus 2)
stdout > @
QQ.txt.sprintf
sprintf
"%d is the %dth number\n"
8
f 6
*
f 6
6