I'm trying to modify the values in a parsed Grammar object with this:
method mutate(Match:D $match --> Match:D) {
for $match.values -> $line {
when $line<content><header-toc><header><taskwiki-content><taskwiki-divider> {
say 'here';
$line<content><header-toc><header><taskwiki-content><taskwiki-divider>.replace-with('');
say $line; # has not been modified;
}
};
return $match;
}
I'm not getting any errors but the $match object is not affected by the replace-with method I'm running.
How do I mutate captures in a Grammar object?
You can't. (Well, you can hang data off them via make, but you can't do what you're thinking you can do.)
A Match object stores the result of a match against some string, and any captures are just .from, .to indexes into that original string.
For example, if you write "bar".match(/a/), the resulting Match object stores the .match method's invocant "bar", and has a .from of 1 and a .to of 2 which represents the captured "a" substring.
The original string remains immutable, and the captured substrings are "virtual" as it were, with nothing you can mutate.
foo.replace-with('');
replace-with does not modify its invocant. It just returns a value (a new string).
Quoting the replace-with doc, with my added bold emphasis:
Returns the invocant string where the Match object is replaced by $replacement.
Note that it's not "the invocant Match object".
The .replace-with method is returning a new string that's a copy of the original input string that was matched against to produce the Match object, with the bit that was matched replaced by the string supplied as the .replace-with method's argument.
Related
I'd like to understand a bit better the 2 functions below. I know it is very compact and understand more or less what it does: it converts each characters of a string into string of '0' and '1'. But...
How does the dot(in front of encodeToByteArray) connect the 's' to encodeToByteArray()?
Where can I find more info about what dot represents?
Also, how and why the code { byte -> binaryStringOf(byte) } can do the job in that place?
How does it "know" that there is a byte with which it calls the function binaryStringOf(byte)
Where can I find more info about it, too?
fun binaryStringOf(message: String): String {
var s: String
s = (message)
.encodeToByteArray()
.joinToString("") { byte -> binaryStringOf(byte) }
return s
}
fun binaryStringOf(b: Byte): String {
return b.toString(2).padStart(8, '0')
}
The formatting above makes things a little bit more confusing, but let me try to explain what is going on.
The = is an assignment operator. It says "assign the variable s to the result of the expression on the right side".
Now we see that message is a parameter in the binaryStringOf function of type String. String is a class which contains a function (also called a method when it is a member of a class) called encodeToByteArray which returns a ByteArray.
ByteArray in turn has a function called joinToString which we're giving two parameters: one of type String, and one of type ((Byte) -> CharSequence) (ie, the function is itself being passed in as a variable, using lambda syntax). Kotlin has some syntactic sugar to make this look nicer when the lambda is the last argument.
So, the statement
s = (message)
.encodeToByteArray()
.joinToString("") { byte -> binaryStringOf(byte) }
means "the variable s is assigned the value that results from calling joinToString on the result of calling encodeToByteArray on message.
Then return s says that the return value from the binaryStringOf should be whatever value was assigned to s.
.encodeToByteArray()
works on the incoming string (message in this case). It returns a ByteArray; so something that represents an array of Byte values.
And on that array object, it invokes the joinToString() method. That method receives various arguments, but only the separator string ("") is provided, and the transform parameter.
Now: transform is a function. It is something that can be invoked, with parameters, and that has to return a specific result.
The key part to understand is that { byte -> ... } is that transform function parameter.
I have read many articles, but there are still things I am having difficulty understanding. Where's the point I can't understand? My questions are in the code. I hope I asked right.
fun main() {
/*
1- Is it argument or parameter in numbers{} block?
where is it sent to the argument? why do we send "4" if it is parameter?
Are all the functions I will write in (eg println) sent to the numbers function? But this HOF can
only take one parameter.
*/
numbers {
/*
2-How does this know that he will work 3 times?
According to the following 3 functions? Is there a for loop logic??
*/
println(it)
"4" // 3- Which one does this represent? f:(String) or ->String?
}
}
fun numbers(f: (String) -> String) {
f("one")
f("two")
f("three")
println(f(" - "))
}
There is no argument or parameter defined in your lambda block above. It's just the content of your lambda function. You've used the implicit single parameter name of it. "4" is the return value of your lambda.
The lambda itself isn't "aware" of how many times it will be called. In this case, it is called four times, because your numbers function invokes the parameter f four times.
A lambda's return value is whatever its last expression evaluates to. In this case, it returns the String "4".
Maybe this will help. Lambda syntax is a convenience. But we can take away each piece of syntactic sugar one at a time to see what it actually means.
All of the code blocks below have the exact same meaning.
Here is your original statement:
numbers {
println(it)
"4"
}
First, when a lambda omits the single parameter, it gets the implicit parameter name it. If we avoid using this sugar, it would look like this:
numbers { inputString ->
println(inputString)
"4"
}
The evaluated value of the last expression in a lambda is what it returns. You can also explicitly write a return statement, but you must specify that you are returning from the lambda, so you have to put its name. So if we put this in, it looks like this:
numbers { inputString ->
println(inputString)
return#numbers "4"
}
When a lambda is the last argument you pass to a function, you can put it outside the parentheses. This is called "trailing lambda". And if the function is the only argument, you don't need parentheses at all. If we skip this convenience, it looks like this:
numbers({ inputString ->
println(inputString)
return#numbers "4"
})
A lambda is just a very compact way of defining a function. If we define the function directly, it looks like this:
numbers(fun(inputString: String): String {
println(inputString)
return "4"
})
The function you are passing is the argument of the numbers() function. You can also define it separately and then pass the function reference like this:
fun myFunction(inputString: String): String {
println(inputString)
return "4"
}
numbers(::myFunction)
I found this piece of code in the kotlin docs:
var stringRepresentation: String
get() = this.toString()
set(value) {
setDataFromString(value) // parses the string and assigns values to other properties
}
I don't understand what this.toString() does here. this refers to the whole object. Why would we want it converted to a string, every time the object is accessed? Should it actually be field.toString()? (but that would be redundant too)
It is probably from an imaginary class that can serialize itself into a String by copying its property values to JSON or some other serialized String format. If these properties are mutable, you would want it to generate a new String each time you get the value. And since it has a setter, this imaginary class's setDataFromString function probably takes JSON or some kind of String representation and deserializes it to its own properties.
The getter is only called when stringRepresentation is accessed.
The setter is not using a backing field, so there's no reason for the getter to use the backing field value.
I am trying to write a step def that matches multiple String values with double quotes:
When I have a HeaderUtil
Then header is generated with fields matching patterns
"""
"\"%s\":\"%s\""
"""
or
"""
"\"%s\":%s"
"""
This stepdef will see that the serialized fields match one of the above patterns in the generated string.
I am looking to have a stepdefinition that will have two arguments that matches one or the other pattern.
Currently, I am getting a parser error:
Caused by: gherkin.lexer.LexingError: Lexing error on line 8: '""" \
"""
"\"%s\":%s"
"""
Is there a way more than one multiline parameter can be passed in a step definition?
I guess it's referenced to this topic of Cucumber Documentation and Custom parameter types
Custom parameter types
You can define custom parameter types to represent types from your own domain. Doing this has the following benefits:
Automatic conversion to custom types
Document and evolve your ubiquitous domain language
Enforce certain patterns
Imagine we want a parameter to match the colors red, blue or yellow (but nothing else). Let's assume a Color class is already defined. This is how we would define a custom color parameter type:
parameterTypeRegistry.defineParameterType(new ParameterType<>(
"color", // name
"red|blue|yellow", // regexp
Color.class, // type
new SingleTransformer<>(new Function<String, Color>() {
#Override
public Color apply(String s) {
return new Color(s);
}
}), // transform
false, // useForSnippets
false // preferForRegexpMatch));
From the Kotlin documentation:
If a function does not return any useful value, its return type is Unit. Unit is a type with only one value — Unit.VALUE. This value does not have to be returned explicitly:
fun printHello(name : String?) : Unit {
if (name != null)
print("Hello, $name!")
else
print("Hi there!")
// We don't need to write 'return Unit.VALUE' or 'return', although we could
}
What is the purpose of Unit-returning in functions? Why is VALUE there? What is this VALUE?
The purpose is the same as C's or Java's void. Only Unit is a proper type, so it can be passed as a generic argument etc.
Why we don't call it "Void": because the word "void" means "nothing", and there's another type, Nothing, that means just "no value at all", i.e. the computation did not complete normally (looped forever or threw an exception). We could not afford the clash of meanings.
Why Unit has a value (i.e. is not the same as Nothing): because generic code can work smoothly then. If you pass Unit for a generic parameter T, the code written for any T will expect an object, and there must be an object, the sole value of Unit.
How to access that value of Unit: since it's a singleton object, just say Unit
The main reason why Unit exists is because of Generic reasons.
Let's use the example from the Kotlin docs.
class Box<T>(t: T) {
var value = t
}
We can have
var box = Box(Unit)
This is why Unit returns a value so the Kotlin can infer it from the type passed into class initialization. Of course, you could also explicitly write it like this,
var box = Box<Unit>(Unit)
but all the same, it must have a return value.
Now, the void keyword in Java in Kotlin is Nothing. Nothing is the last but one type in the type hierarchy in Kotlin with the last one being Nothing? (Nullable Nothing). This does not return any value at all. Because it doesn't return any value at all, we can't pass it as a type in the above code.
var box = Box(Nothing) //This will return an Error
UNIT actually contains valuable information, it basically just means "DONE". It just returns the information to the caller, that the method has been finished. This is a real piece of information so it can be seen as the return value of a method.