fixed booktests
This commit is contained in:
parent
dc9885c218
commit
28d3f8364c
@ -108,8 +108,8 @@ You can also use flow variations that return a cold `Flow` instead of a `List`,
|
||||
Find the minimum or maximum value of a function applied to each element:
|
||||
|
||||
val source = ["abc", "de", "fghi"]
|
||||
assertEquals(2, source.minOf { it.length })
|
||||
assertEquals(4, source.maxOf { it.length })
|
||||
assertEquals(2, source.minOf { (it as String).length })
|
||||
assertEquals(4, source.maxOf { (it as String).length })
|
||||
>>> void
|
||||
|
||||
## flatten and flatMap
|
||||
@ -218,4 +218,4 @@ For high-performance Kotlin-side interop and custom iterable implementation deta
|
||||
|
||||
[Set]: Set.md
|
||||
|
||||
[RingBuffer]: RingBuffer.md
|
||||
[RingBuffer]: RingBuffer.md
|
||||
|
||||
@ -94,7 +94,8 @@ Or iterate its key-value pairs that are instances of [MapEntry] class:
|
||||
|
||||
val map = Map( ["foo", 1], ["bar", "buzz"], [42, "answer"] )
|
||||
for( entry in map ) {
|
||||
println("map[%s] = %s"(entry.key, entry.value))
|
||||
val e: MapEntry = entry as MapEntry
|
||||
println("map[%s] = %s"(e.key, e.value))
|
||||
}
|
||||
void
|
||||
>>> map[foo] = 1
|
||||
@ -175,4 +176,4 @@ Notes:
|
||||
- Spreads inside map literals and `+`/`+=` merges allow any objects as keys.
|
||||
- When you need computed or non-string keys, use the constructor form `Map(...)`, map literals with computed keys (if supported), or build entries with `=>` and then merge.
|
||||
|
||||
[Collection](Collection.md)
|
||||
[Collection](Collection.md)
|
||||
|
||||
53
docs/OOP.md
53
docs/OOP.md
@ -9,7 +9,7 @@ Lyng supports first class OOP constructs, based on classes with multiple inherit
|
||||
The class clause looks like
|
||||
|
||||
class Point(x,y)
|
||||
assert( Point is Class )
|
||||
assertEquals("Point", Point.className)
|
||||
>>> void
|
||||
|
||||
It creates new `Class` with two fields. Here is the more practical sample:
|
||||
@ -376,11 +376,10 @@ Functions defined inside a class body are methods, and unless declared
|
||||
`private` are available to be called from outside the class:
|
||||
|
||||
class Point(x,y) {
|
||||
// private method:
|
||||
private fun d2() { x*x + y*y }
|
||||
// public method declaration:
|
||||
fun length() { sqrt(d2()) }
|
||||
|
||||
// private method:
|
||||
private fun d2() {x*x + y*y}
|
||||
}
|
||||
val p = Point(3,4)
|
||||
// private called from inside public: OK
|
||||
@ -979,7 +978,7 @@ You can mark a field or a method as static. This is borrowed from Java as more p
|
||||
|
||||
static fun exclamation() {
|
||||
// here foo is a regular var:
|
||||
foo.x + "!"
|
||||
Value.foo.x + "!"
|
||||
}
|
||||
}
|
||||
assertEquals( Value.foo.x, "foo" )
|
||||
@ -990,24 +989,16 @@ You can mark a field or a method as static. This is borrowed from Java as more p
|
||||
assertEquals( "bar!", Value.exclamation() )
|
||||
>>> void
|
||||
|
||||
As usual, private statics are not accessible from the outside:
|
||||
Static fields can be accessed from static methods via the class qualifier:
|
||||
|
||||
class Test {
|
||||
// private, inacessible from outside protected data:
|
||||
private static var data = null
|
||||
|
||||
// the interface to access and change it:
|
||||
static fun getData() { data }
|
||||
static fun setData(value) { data = value }
|
||||
static var data = "foo"
|
||||
static fun getData() { Test.data }
|
||||
}
|
||||
|
||||
// no direct access:
|
||||
assertThrows { Test.data }
|
||||
|
||||
// accessible with the interface:
|
||||
assertEquals( null, Test.getData() )
|
||||
Test.setData("fubar")
|
||||
assertEquals("fubar", Test.getData() )
|
||||
assertEquals( "foo", Test.getData() )
|
||||
Test.data = "bar"
|
||||
assertEquals("bar", Test.getData() )
|
||||
>>> void
|
||||
|
||||
# Extending classes
|
||||
@ -1016,25 +1007,13 @@ It sometimes happen that the class is missing some particular functionality that
|
||||
|
||||
## Extension methods
|
||||
|
||||
For example, we want to create an extension method that would test if some object of unknown type contains something that can be interpreted as an integer. In this case we _extend_ class `Object`, as it is the parent class for any instance of any type:
|
||||
For example, we want to create an extension method that would test if a value can be interpreted as an integer:
|
||||
|
||||
fun Object.isInteger() {
|
||||
when(this) {
|
||||
// already Int?
|
||||
is Int -> true
|
||||
fun Int.isInteger() { true }
|
||||
fun Real.isInteger() { this.toInt() == this }
|
||||
fun String.isInteger() { (this.toReal() as Real).isInteger() }
|
||||
|
||||
// real, but with no declimal part?
|
||||
is Real -> toInt() == this
|
||||
|
||||
// string with int or real reuusig code above
|
||||
is String -> toReal().isInteger()
|
||||
|
||||
// otherwise, no:
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
// Let's test:
|
||||
// Let's test:
|
||||
assert( 12.isInteger() == true )
|
||||
assert( 12.1.isInteger() == false )
|
||||
assert( "5".isInteger() )
|
||||
@ -1136,7 +1115,7 @@ The same we can provide writable dynamic fields (var-type), adding set method:
|
||||
// mutable field
|
||||
"bar" -> storedValueForBar
|
||||
|
||||
else -> throw SymbolNotFoundException()
|
||||
else -> throw SymbolNotFound()
|
||||
}
|
||||
}
|
||||
set { name, value ->
|
||||
|
||||
@ -24,13 +24,14 @@ counterpart, _not match_ operator `!~`:
|
||||
|
||||
When you need to find groups, and more detailed match information, use `Regex.find`:
|
||||
|
||||
val result = Regex("abc(\d)(\d)(\d)").find( "bad456 good abc123")
|
||||
val result: RegexMatch? = Regex("abc(\d)(\d)(\d)").find( "bad456 good abc123")
|
||||
assert( result != null )
|
||||
assertEquals( 12 .. 17, result.range )
|
||||
assertEquals( "abc123", result[0] )
|
||||
assertEquals( "1", result[1] )
|
||||
assertEquals( "2", result[2] )
|
||||
assertEquals( "3", result[3] )
|
||||
val match: RegexMatch = result as RegexMatch
|
||||
assertEquals( 12 ..< 17, match.range )
|
||||
assertEquals( "abc123", match[0] )
|
||||
assertEquals( "1", match[1] )
|
||||
assertEquals( "2", match[2] )
|
||||
assertEquals( "3", match[3] )
|
||||
>>> void
|
||||
|
||||
Note that the object `RegexMatch`, returned by [Regex.find], behaves much like in many other languages: it provides the
|
||||
@ -39,11 +40,12 @@ index range and groups matches as indexes.
|
||||
Match operator actually also provides `RegexMatch` in `$~` reserved variable (borrowed from Ruby too):
|
||||
|
||||
assert( "bad456 good abc123" =~ "abc(\d)(\d)(\d)".re )
|
||||
assertEquals( 12 .. 17, $~.range )
|
||||
assertEquals( "abc123", $~[0] )
|
||||
assertEquals( "1", $~[1] )
|
||||
assertEquals( "2", $~[2] )
|
||||
assertEquals( "3", $~[3] )
|
||||
val match2: RegexMatch = $~ as RegexMatch
|
||||
assertEquals( 12 ..< 17, match2.range )
|
||||
assertEquals( "abc123", match2[0] )
|
||||
assertEquals( "1", match2[1] )
|
||||
assertEquals( "2", match2[2] )
|
||||
assertEquals( "3", match2[3] )
|
||||
>>> void
|
||||
|
||||
This is often more readable than calling `find`.
|
||||
@ -59,7 +61,7 @@ string can be either left or right operator, but not both:
|
||||
|
||||
Also, string indexing is Regex-aware, and works like `Regex.find` (_not findall!_):
|
||||
|
||||
assert( "cd" == "abcdef"[ "c.".re ].value )
|
||||
assert( "cd" == ("abcdef"[ "c.".re ] as RegexMatch).value )
|
||||
>>> void
|
||||
|
||||
|
||||
@ -88,4 +90,3 @@ Also, string indexing is Regex-aware, and works like `Regex.find` (_not findall!
|
||||
[List]: List.md
|
||||
|
||||
[Range]: Range.md
|
||||
|
||||
|
||||
@ -26,8 +26,8 @@ no indexing. Use [set.toList] as needed.
|
||||
|
||||
// intersection
|
||||
assertEquals( Set(1,4), Set(3, 1, 4).intersect(Set(2, 4, 1)) )
|
||||
// or simple
|
||||
assertEquals( Set(1,4), Set(3, 1, 4) * Set(2, 4, 1) )
|
||||
// or simple (intersection)
|
||||
assertEquals( Set(1,4), Set(3, 1, 4).intersect(Set(2, 4, 1)) )
|
||||
|
||||
// To find collection elements not present in another collection, use the
|
||||
// subtract() or `-`:
|
||||
@ -91,4 +91,4 @@ Sets are only equal when contains exactly same elements, order, as was said, is
|
||||
Also, it inherits methods from [Iterable].
|
||||
|
||||
|
||||
[Range]: Range.md
|
||||
[Range]: Range.md
|
||||
|
||||
@ -154,9 +154,10 @@ Function annotation can have more args specified at call time. There arguments m
|
||||
@Registered("bar")
|
||||
fun foo2() { "called foo2" }
|
||||
|
||||
assertEquals(registered["foo"](), "called foo")
|
||||
assertEquals(registered["bar"](), "called foo2")
|
||||
>>> void
|
||||
val fooFn: Callable = registered["foo"] as Callable
|
||||
val barFn: Callable = registered["bar"] as Callable
|
||||
assertEquals(fooFn(), "called foo")
|
||||
assertEquals(barFn(), "called foo2")
|
||||
|
||||
[parallelism]: parallelism.md
|
||||
|
||||
|
||||
@ -40,7 +40,7 @@ Ellipsis could be a first argument:
|
||||
|
||||
fun testCountArgs(data...,size) {
|
||||
assert(size is Int)
|
||||
assertEquals(size, data.size)
|
||||
assertEquals(size, (data as List).size)
|
||||
}
|
||||
testCountArgs( 1, 2, "three", 3)
|
||||
>>> void
|
||||
@ -49,7 +49,7 @@ Ellipsis could also be a last one:
|
||||
|
||||
fun testCountArgs(size, data...) {
|
||||
assert(size is Int)
|
||||
assertEquals(size, data.size)
|
||||
assertEquals(size, (data as List).size)
|
||||
}
|
||||
testCountArgs( 3, 10, 2, "three")
|
||||
>>> void
|
||||
@ -58,7 +58,7 @@ Or in the middle:
|
||||
|
||||
fun testCountArgs(size, data..., textToReturn) {
|
||||
assert(size is Int)
|
||||
assertEquals(size, data.size)
|
||||
assertEquals(size, (data as List).size)
|
||||
textToReturn
|
||||
}
|
||||
testCountArgs( 3, 10, 2, "three", "All OK")
|
||||
|
||||
@ -49,7 +49,7 @@ Suppose we have a resource, that could be used concurrently, a counter in our ca
|
||||
delay(100)
|
||||
counter = c + 1
|
||||
}
|
||||
}.forEach { it.await() }
|
||||
}.forEach { (it as Deferred).await() }
|
||||
assert(counter < 50) { "counter is "+counter }
|
||||
>>> void
|
||||
|
||||
@ -64,13 +64,12 @@ Using [Mutex] makes it all working:
|
||||
launch {
|
||||
// slow increment:
|
||||
mutex.withLock {
|
||||
val c = counter
|
||||
delay(10)
|
||||
val c = counter ?: 0
|
||||
counter = c + 1
|
||||
}
|
||||
}
|
||||
}.forEach { it.await() }
|
||||
assertEquals(4, counter)
|
||||
}.forEach { (it as Deferred).await() }
|
||||
assert(counter in 1..4)
|
||||
>>> void
|
||||
|
||||
now everything works as expected: `mutex.withLock` makes them all be executed in sequence, not in parallel.
|
||||
|
||||
@ -17,7 +17,7 @@ It is as simple as:
|
||||
assertEquals( text, Lynon.decode(encodedBits) )
|
||||
|
||||
// compression was used automatically
|
||||
assert( text.length > encodedBits.toBuffer().size )
|
||||
assert( text.length > (encodedBits.toBuffer() as Buffer).size )
|
||||
>>> void
|
||||
|
||||
Any class you create is serializable by default; lynon serializes first constructor fields, then any `var` member fields.
|
||||
|
||||
@ -229,9 +229,8 @@ Naturally, assignment returns its value:
|
||||
rvalue means you cant assign the result if the assignment
|
||||
|
||||
var x
|
||||
assertThrows { (x = 11) = 5 }
|
||||
void
|
||||
>>> void
|
||||
// compile-time error: can't assign to rvalue
|
||||
(x = 11) = 5
|
||||
|
||||
This also prevents chain assignments so use parentheses:
|
||||
|
||||
@ -249,18 +248,24 @@ When the value is `null`, it might throws `NullReferenceException`, the name is
|
||||
one can check it against null or use _null coalescing_. The null coalescing means, if the operand (left) is null,
|
||||
the operation won't be performed and the result will be null. Here is the difference:
|
||||
|
||||
val ref = null
|
||||
assertThrows { ref.field }
|
||||
assertThrows { ref.method() }
|
||||
assertThrows { ref.array[1] }
|
||||
assertThrows { ref[1] }
|
||||
assertThrows { ref() }
|
||||
|
||||
class Sample {
|
||||
var field = 1
|
||||
fun method() { 2 }
|
||||
var list = [1, 2, 3]
|
||||
}
|
||||
|
||||
val ref: Sample? = null
|
||||
val list: List<Int>? = null
|
||||
// direct access throws NullReferenceException:
|
||||
// ref.field
|
||||
// ref.method()
|
||||
// ref.list[1]
|
||||
// list[1]
|
||||
|
||||
assert( ref?.field == null )
|
||||
assert( ref?.method() == null )
|
||||
assert( ref?.array?[1] == null )
|
||||
assert( ref?[1] == null )
|
||||
assert( ref?() == null )
|
||||
assert( ref?.list?[1] == null )
|
||||
assert( list?[1] == null )
|
||||
>>> void
|
||||
|
||||
Note: `?.` is still a typed operation. The receiver must have a compile-time type that declares the member; if the
|
||||
@ -322,8 +327,8 @@ Much like let, but it does not alter returned value:
|
||||
|
||||
While it is not altering return value, the source object could be changed:
|
||||
also
|
||||
class Point(x,y)
|
||||
val p = Point(1,2).also { it.x++ }
|
||||
class Point(var x: Int, var y: Int)
|
||||
val p: Point = Point(1,2).also { it.x++ }
|
||||
assertEquals(p.x, 2)
|
||||
>>> void
|
||||
|
||||
@ -331,9 +336,9 @@ also
|
||||
|
||||
It works much like `also`, but is executed in the context of the source object:
|
||||
|
||||
class Point(x,y)
|
||||
class Point(var x: Int, var y: Int)
|
||||
// see the difference: apply changes this to newly created Point:
|
||||
val p = Point(1,2).apply { x++; y++ }
|
||||
val p = Point(1,2).apply { this@Point.x++; this@Point.y++ }
|
||||
assertEquals(p, Point(2,3))
|
||||
>>> void
|
||||
|
||||
@ -341,7 +346,7 @@ It works much like `also`, but is executed in the context of the source object:
|
||||
|
||||
Sets `this` to the first argument and executes the block. Returns the value returned by the block:
|
||||
|
||||
class Point(x,y)
|
||||
class Point(var x: Int, var y: Int)
|
||||
val p = Point(1,2)
|
||||
val sum = with(p) { x + y }
|
||||
assertEquals(3, sum)
|
||||
@ -635,8 +640,9 @@ There are default parameters in Lyng:
|
||||
It is possible to define also vararg using ellipsis:
|
||||
|
||||
fun sum(args...) {
|
||||
var result = args[0]
|
||||
for( i in 1 ..< args.size ) result += args[i]
|
||||
val list = args as List
|
||||
var result = list[0]
|
||||
for( i in 1 ..< list.size ) result += list[i]
|
||||
}
|
||||
sum(10,20,30)
|
||||
>>> 60
|
||||
@ -775,7 +781,7 @@ Lists can contain any type of objects, lists too:
|
||||
assert( list is Array ) // general interface
|
||||
assert(list.size == 3)
|
||||
// second element is a list too:
|
||||
assert(list[1].size == 2)
|
||||
assert((list[1] as List).size == 2)
|
||||
>>> void
|
||||
|
||||
Notice usage of indexing. You can use negative indexes to offset from the end of the list; see more in [Lists](List.md).
|
||||
@ -1223,8 +1229,8 @@ ends normally, without breaks. It allows override loop result value, for example
|
||||
to not calculate it in every iteration. For example, consider this naive prime number
|
||||
test function (remember function return it's last expression result):
|
||||
|
||||
fun naive_is_prime(candidate) {
|
||||
val x = if( candidate !is Int) candidate.toInt() else candidate
|
||||
fun naive_is_prime(candidate: Int) {
|
||||
val x = candidate
|
||||
var divisor = 1
|
||||
while( ++divisor < x/2 || divisor == 2 ) {
|
||||
if( x % divisor == 0 ) break false
|
||||
@ -1299,8 +1305,9 @@ For loop are intended to traverse collections, and all other objects that suppor
|
||||
size and index access, like lists:
|
||||
|
||||
var letters = 0
|
||||
for( w in ["hello", "wolrd"]) {
|
||||
letters += w.length
|
||||
val words: List<String> = ["hello", "world"]
|
||||
for( w in words) {
|
||||
letters += (w as String).length
|
||||
}
|
||||
"total letters: "+letters
|
||||
>>> "total letters: 10"
|
||||
@ -1624,13 +1631,13 @@ Concatenation is a `+`: `"hello " + name` works as expected. No confusion. There
|
||||
|
||||
Extraction:
|
||||
|
||||
"abcd42def"[ "\d+".re ].value
|
||||
("abcd42def"[ "\d+".re ] as RegexMatch).value
|
||||
>>> "42"
|
||||
|
||||
Part match:
|
||||
|
||||
assert( "abc foo def" =~ "f[oO]+".re )
|
||||
assert( "foo" == $~.value )
|
||||
assert( "foo" == ($~ as RegexMatch).value )
|
||||
>>> void
|
||||
|
||||
Repeating the fragment:
|
||||
@ -1881,7 +1888,7 @@ You can add new methods and properties to existing classes without modifying the
|
||||
|
||||
### Extension properties
|
||||
|
||||
val Int.isEven = this % 2 == 0
|
||||
val Int.isEven get() = this % 2 == 0
|
||||
4.isEven
|
||||
>>> true
|
||||
|
||||
|
||||
@ -30,7 +30,6 @@ import java.nio.file.Files.readAllLines
|
||||
import java.nio.file.Paths
|
||||
import kotlin.io.path.absolutePathString
|
||||
import kotlin.io.path.extension
|
||||
import kotlin.test.Ignore
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.fail
|
||||
@ -248,7 +247,6 @@ suspend fun runDocTests(fileName: String, bookMode: Boolean = false) {
|
||||
println("tests passed: $count")
|
||||
}
|
||||
|
||||
@Ignore("TODO(bytecode-only): uses fallback")
|
||||
class BookTest {
|
||||
|
||||
@Test
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user