How to invoke one function from another in PlantUML preprocessing? - uml

I am using PlantUML and want to use the pre-processing feature.
I am getting an error when i try to call a return function from another returning function.
I don't know what I am doing wrong but I get an error. I bet it is something simple but I can't quite figure it out.
Here is the code.
#startuml
!$longestActivityLength = 20
!function $pmax($num1,$num2)
!if(num1 > num2){ return num1 }
!if(num2 > num1){ return num2 }
!if(num1 == num2){ return num1 }
!endfunction
!function $fixLen($name)
!$maxNum = $pmax($longestActivityLength,%strlen($name))
!return sprintf("%-*s%s%*s", maxNum / 2, 0), "", $name, ceiling(maxNum / 2, 0)), "")
!endfunction
skinparam swimlaneWidth same
|A|
:foo1;
:$fixLen("foo2");
|b|
:foo3 which is very long;
#enduml
and here is the error.
My guess is that this is a syntax error. What is wrong with the code?

Related

How to print more than one value in the same line?

A simple example
Print("This is a number {0}", 1) // results in 4
How can I print 1 2 3 in the same line?
I have tried
Print(1, 2, 3) // Does not work
The forloop also does not work.
The while loop below prints the elements but each in a separate line since we do not have control over the line feed character \n:
fn Main() -> i32 {
var a: [i32;3] = (1, 2, 3); // Define array containing the numbers 1,2,3
var i:i32 =0;
while(i<3){
Print("{0}", a[i]);
i= i+1;
}
return 0;
}
which results in
1
2
3
here is the code
How can I get 1 2 3?
Short explanation: Providing more than 2 arguments to Print is currently not supported, so is not including a line break.
Details
This is definitely something that will change in the future, as the language is in its early design phases. You can find the source for Print as an instrinsic (non-carbon native) here: https://github.com/carbon-language/carbon-lang/blob/trunk/explorer/interpreter/type_checker.cpp#L2297
case IntrinsicExpression::Intrinsic::Print:
// TODO: Remove Print special casing once we have variadics or
// overloads. Here, that's the name Print instead of __intrinsic_print
// in errors.
if (args.size() < 1 || args.size() > 2) {
return CompilationError(e->source_loc())
<< "Print takes 1 or 2 arguments, received " << args.size();
}
CARBON_RETURN_IF_ERROR(ExpectExactType(
e->source_loc(), "Print argument 0", arena_->New<StringType>(),
&args[0]->static_type(), impl_scope));
if (args.size() >= 2) {
CARBON_RETURN_IF_ERROR(ExpectExactType(
e->source_loc(), "Print argument 1", arena_->New<IntType>(),
&args[1]->static_type(), impl_scope));
}
If you look at the code you will also see that the type of input variable is limited to just integer types. It would be easy enough create a PR to manually add support for 2-3 if you want :)

Actionscript 3 error 1176 : Comparison between a value with static type Function and a possibly unrelated type int

I want to make coding about the final score display. If someone has done 10 multiple choice questions and he clicks on the final score button, then his final score will appear along with the description. The score will be made in a range according to the category, namely 1-59 = Under Average, 60-79 = Average, and 80-100 = Above Average.
I've tried coding it but I found error 1176 on line 7 and 11.
Can you help me fix it?
finalscorebutton.addEventListener(MouseEvent.CLICK, finalscore);
function finalscore(event:MouseEvent):void
{
multiplechoicefinalscore.text = sumofscores;
var finalscore:String = finalscore.toString;
finalscore = multiplechoicefinalscore..text;
if(finalscore.toString < 60){
description.text =
"UNDER AVERAGE.";
}
else if(finalscore.toString >= 60 && finalscore.toString <=79){
description.text =
"AVERAGE.";
}
else{
description.text =
"ABOVE AVERAGE.";
}
}
There are multiple syntax and logic errors.
Something.toString is a reference to a method, you probably mean Something.toString() which calls the said method and returns a text representation of whatever Something is.
You don't need a text representation because you want to compare numbers, you need a numeric representation (which is either int, uint or Number).
There are 2 dots in multiplechoicefinalscore..text, what does it even mean?
There is function finalscore and then you define var finalscore, defining things with the same names is a bad idea in general.
You should keep your script formatted properly, otherwise reading it and understanding would be a pain.
So, I assume you have the user's result is in sumofscores. I'm not sure if the script below will actually work as is, but at least it is logically and syntactically correct:
finalscorebutton.addEventListener(MouseEvent.CLICK, onFinal);
function onFinal(e:MouseEvent):void
{
// Ok, let's keep this one, I think you are putting
// the score result into some kind of TextField.
multiplechoicefinalscore.text = sumofscores;
// Get a definitely numeric representation of the score.
var aScore:int = int(sumofscores);
// In terms of logic, putting the complicated condition case
// under the "else" statement will simplify the program.
if (aScore < 60)
{
description.text = "UNDER AVERAGE.";
}
else if (aScore > 79)
{
description.text = "ABOVE AVERAGE.";
}
else
{
description.text = "AVERAGE.";
}
}

Implicit coercion of a value of type int to an unrelated type String

There is an object called bird. I want to go to a new scene 2, 1 after that bird reaches location of bird.y = -575.
However, when debugging the code, I got
Scene 1, Layer 'actions', Frame 1, Line 44 1067: Implicit coercion of a value of type int to an unrelated type String.
How to fix it?
Code
import flash.events.MouseEvent;
import flash.display.MovieClip;
stop();
var birdVelocity:int = 0;
var stageGravity:int = 2;
function BirdFall(event:Event):void
{
bird.y = bird.y + birdVelocity;
birdVelocity = birdVelocity + stageGravity;
}
stage.addEventListener(Event.ENTER_FRAME, BirdFall);
function FlyBird(event:MouseEvent):void
{
birdVelocity = -10;
bird.gotoAndStop(2);
}
stage.addEventListener(MouseEvent.CLICK, FlyBird);
if (bird.y == 575) {
gotoAndPlay("Scene 2", 1)
}
Honestly have no idea why it's set up like this as the gotoAndPlay function on Adobe's actual page says you're supposed to put where you want to go first and the frame second, but it's swapped for some unknown reason, so you're actually supposed to write it as:
gotoAndPlay(1, "Scene 2");
I had the same problem and found out you're supposed to have the frame first and it worked for me.

Negative values returned from file in NXC

I am saving values to a .csv file in NXC(Not eXactly C) and then calling on them ata later point in time. The problem I am having is when calling any negative values back from a cell it is displayed as 0123 instead of -123 which is throwing all my additional calculations off.
The current code is:
OpenFileRead("map.csv", fSize, count);
until (eof == true) {
ReadLnString(count, val);
int lstFwd = StrToNum(val);
NumOut(0,LCD_LINE1,lstFwd);
}
while(true);
Can anyone explain how to rectify this issue as it is causing me a great deal of stress now.
StrToNum should convert negativ numbers. Its a bit strange that an integer number starts with 0. You should also use Enhanced NBC/NXC firmware.
First: You should always clear the screen before writing some output!
Use:
NumOut(0,LCD_LINE1,lstFwd, DRAW_OPT_CLEAR_LINE);
If the problem still exists try:
string val;
OpenFileRead("map.csv", fSize, count);
until (eof == true) {
ReadLnString(count, val);
int lstFwd = StrToNum(val);
if(SubStr(val, 0, 1) == "-") lstFwd *= -1; // Check if first char is "-"
NumOut(0,LCD_LINE1,lstFwd, DRAW_OPT_CLEAR_LINE);
}
while(true);

Is There a Groovier Way To Add Dashes to a String?

I have the following code, which works, but I'm wondering if there is a "groovier" way of doing this:
/**
* 10 digit - #-######-##-#
* 13 digit - ###-#-######-##-#
* */
private formatISBN(String isbn) {
if (isbn?.length() == 10) {
def part1 = isbn.substring(0, 1)
def part2 = isbn.substring(1, 7)
def part3 = isbn.substring(7, 9)
def part4 = isbn.substring(9, 10)
return "${part1}-${part2}-${part3}-${part4}"
} else if (isbn?.length() == 13) {
def part1 = isbn.substring(0, 3)
def part2 = isbn.substring(3, 4)
def part3 = isbn.substring(4, 10)
def part4 = isbn.substring(10, 12)
def part5 = isbn.substring(12, 13)
return "${part1}-${part2}-${part3}-${part4}-${part5}"
} else {
return isbn
}
}
You could first use the [] string operator to get the substrings instead of substring and drop the intermediate variables. For example in the case for length == 10:
"${isbn[0]}-${isbn[1..6]}-${isbn[7..8]}-${isbn[9]}"
Now, there is a bit of repetition there. You can get instead first get all the isbn segments and then .join them with '-':
[isbn[0], isbn[1..6], isbn[7..8], isbn[9]].join('-')
And, even further, instead of referencing isbn every time, you can make a list of the ranges you want to get and then get them all the same time using collect:
[0, 1..6, 7..8, 9].collect { isbn[it] }.join('-')
If you're going for code golfing, you can also do:
('-'+isbn)[1, 0, 2..7, 0, 8..9, 0, 10]
I'll leave it to you to figure out how that works, but i guess it's probably not a good idea to leave that on production code, unless you want to surprise future maintainers hehe.
Also, notice that the format when length == 13 is the same as for length == 10 but with a different prefix, you can then reuse the same function in that case. The whole function (with a couple of tests) would be:
/**
* 10 digit - #-######-##-#
* 13 digit - ###-#-######-##-#
**/
def formatIsbn(isbn) {
switch (isbn?.length()) {
case 10: return [0, 1..6, 7..8, 9].collect { isbn[it] }.join('-')
case 13: return isbn.take(3) + '-' + formatIsbn(isbn.drop(3))
default: return isbn
}
}
assert formatIsbn('abcdefghij') == 'a-bcdefg-hi-j'
assert formatIsbn('abcdefghijklm') == 'abc-d-efghij-kl-m'
Now, i think there are some bad smells in that code. Can isbn be null? At least to me, this doesn't look like a function that needs to bother about the nullity of its argument, or at least that's not clear by reading its name (it should be called something like formatIsbnOrNull instead if both ISBN strings and null values are accepted). If null values are not valid, then let it blow up with a NullPointerException when accessing isbn.length() so the caller know they have passed a wrong argument, instead of silently returning the same null.
The same goes for the return ISBN at the end. Is it expected for that function to receive a string that's neither 10 nor 13 characters long? If not, better throw new IllegalArgumentException() and let the caller know they have called it wrongly.
Finally, i'm not sure if this is the most "readable" solution. Another possible solution is having a string for the format, like '###-#-######-##-#' and then replace the #s by the isbn characters. I think it might be more self-documenting:
def formatIsbn(isbn) {
def format = [
10: '#-######-##-#',
13: '###-#-######-##-#'
][isbn.length()]
def n = 0
format.replaceAll(/#/) { isbn[n++] }
}
Consider adding the method to the String class, as shown here. Note that this answer is a spin on a clever suggestion in epidemian's answer (re: collect).
Note:
This code augments String with asIsbn().
The range [0..2] does not need the call to asIsbn(), but the symmetry of using collect twice is irresistable.
Groovy returns the last expression in if/else, so 'return' is not necessary
/**
* 10 digit - #-######-##-#
* 13 digit - ###-#-######-##-#
**/
String.metaClass.asIsbn = { ->
if (delegate.length() == 10) {
[0, 1..6, 7..8, 9].collect { delegate[it] }.join('-')
} else if (delegate.length() == 13) {
[0..2, 3..12].collect { delegate[it].asIsbn() }.join('-')
} else {
delegate
}
}
assert "abcdefghij".asIsbn() == 'a-bcdefg-hi-j'
assert "abcdefghijklm".asIsbn() == 'abc-d-efghij-kl-m'
assert "def".asIsbn() == "def"
String s = null
assert s?.asIsbn() == null
I would try using Regex... I think it's pretty much readable if you know how to use regex, and it's javascript inspired syntax in groovy is pretty cool also.
One more thing: it's pretty clear, looking at the capture groups, what your string looks like for the desired formatting.
private formatISBN(String isbn) {
if (isbn?.length() == 10) {
m = isbn =~ /(\d{1})(\d{6})(\d{2})(\d{1})/
return "${m[0][1]}-${m[0][2]}-${m[0][3]}-${m[0][4]}"
} else if (isbn?.length() == 13) {
m = isbn =~ /(\d{3})(\d{1})(\d{6})(\d{2})(\d{1})/
return "${m[0][1]}-${m[0][2]}-${m[0][3]}-${m[0][4]}-${m[0][5]}"
} else {
return isbn
}
}
Btw, #epidemian suggestion using backreferences is great! I think the code would look like:
private formatISBN(String isbn) {
if (isbn?.length() == 10) {
return isbn.replaceAll(/(\d{1})(\d{6})(\d{2})(\d{1})/, '$1-$2-$3-$4')
} else if (isbn?.length() == 13) {
return isbn.replaceAll(/(\d{3})(\d{1})(\d{6})(\d{2})(\d{1})/, '$1-$2-$3-$4-$5')
} else {
return isbn
}
}
Dunno if I like this any better. I'd make the position map a static final, too.
private isbnify(String isbn) {
def dashesAt = [ 10: [[0,1], [1,7], [7,9], [9,10]],
13: [[0,3], [3,4], [4,10], [10,12], [12,13]]]
def dashes = dashesAt[isbn?.length()]
(dashes == null) ? isbn
: dashes.collect { isbn.substring(*it) }.join('-')
}
Ranges make for a bit less clutter, IMO:
private isbnify3(String isbn) {
def dashesAt = [ 10: [0, 1..6, 7..8, 9],
13: [0..2, 3, 4..9, 10..11, 12]]
def dashes = dashesAt[isbn?.length()]
dashes == null ? isbn : dashes.collect { isbn[it] }.join("-")
}
With an inject-with-two-accumulators it should be easy to do a list-of-dash-positions version, too.
This should be a comment to #everton, but I don't have the 50 reputation needed to do that yet. So this answer is really just a suggested variation on #everton's answer.
One less regex by making the first 3 digits optional. The downside is having to remove a leading '-' if the ISBN is 10 characters. (I also prefer \d over \d{1}.)
private formatISBN(String isbn) {
String result = isbn.replaceAll(/^(\d{3})?(\d)(\d{6})(\d{2})(\d)$/,
'$1-$2-$3-$4-$5')
if (result) {
return result.startsWith('-') ? result[1..-1] : result
} else {
return isbn // return value unchanged, pattern didn't match
}
}
println formatISBN('1234567890')
println formatISBN('9991234567890')
println formatISBN('123456789') // test an ISBN that's too short
println formatISBN('12345678901234') // test an ISBN that's too long

Resources