I've noticed some strange behaviour when resolving Grails messages using the g.message tag. In my properties file I've defined this message:
deleted={0} has been deleted
If I resolve this with:
Long id = 1878L
message(code: 'festival.deleted', args: [id.toString()])
the result is:
1878 has been deleted
which is what I would have expected. However, if I resolve it with:
Long id = 1878L
message(code: 'festival.deleted', args: [id])
the result is:
1,878 has been deleted
It's not clear to me why the number is formatted as "1,878" before it's substituted into the message. I thought perhaps toString() is called on all message arguments if they're not already of type String, but this doesn't appear to explain this behaviour, because
id.toString() == "1878"
The g.message tag uses Java's MessageFormat to generate the text output. MessageFormat has several default ways of formatting arguments if no argument format is specified. {0} has been deleted says there's an argument but doesn't say how to format it.
If the argument is a String, the string is inserted into the message. If the argument is a Number, NumberFormat is used.
groovy:000> NumberFormat.getInstance().format(1878L)
===> 1,878
There's a nice table in the docs for format() that breaks down what happens in what cases. If you want to use a Long as your argument without calling toString() on it, you can change your argument to {0,number,#} which would be equivalent to
groovy:000> new DecimalFormat("#", DecimalFormatSymbols.getInstance()).format(1878L)
===> 1878
Related
I'm new at Dart and I'm taking a course but I don't know if I'm doing something wrong at this particular lesson. I have almost the exact code as my instructor, yet I get an Error instead of a "null" result. This is the code:
import 'package:hello_dart/hello_dart.dart' as hello_dart;
// we can also add exceptions on the parameters using "[]"
//
void main(List<String> arguments) {
var name = sayHello("Pink", "Unicorn");
print(name);
}
String sayHello(String name, String lastName, [int age]) => "$name "
"$lastName $age";
The idea of this lesson is to create exceptions on the function's parameters. On this example, he adds [] on "int age" to add an exception and erases "$age". With that he gets "Pink Unicorn null" as a result.
But I get instead this error:
The parameter 'age' can't have a value of 'null' because of its type 'int', but the implicit default value is 'null'.
Try adding either an explicit non-'null' default value or the 'required' modifier.
String sayHello(String name, String lastName, [int age])
^^^
The course is at least four years old, so maybe there was an update where Dart no longer gives a "null" result to an "int" value ? or am I doing something wrong ? https://prnt.sc/cq-YmQgPVx1R
Yes, this course is outdated, it missed dart-null-safety.
Those are optional positional parameters. Please do not call that "exception", since "exception" is a word generally used for something totally unrelated in almost all programming languages including Dart.
Since an int can be longer be null, your optional positional parameter needs to be of type int? to be able to have null as a value.
So this:
void main(List<String> arguments) {
var name = sayHello("Pink", "Unicorn");
print(name);
}
String sayHello(String name, String lastName, [int? age]) => "$name "
"$lastName $age";
Will produce the output:
Pink Unicorn null
For more information on "null safety" and why it's a really great feature, see https://dart.dev/null-safety
Try to use tutorials from the last year at least. Flutter and Dart change fast, to the better, and you should not start learning something only to have outdated knowledge when you are done. Make sure you are learning from a source that is current.
I have this method:
Future<Either<Failure, WorkEntity>> updateWorkEntity({int id, String title, TimeType timeType, int times, DateTime executed})
that is being called like this:
repository.updateWorkEntity(id: workEntity.id, executed: DateTime.now())
the id I can control in a test, but the "DateTime.now()" I ofcourse can not. What I tried was this in my test:
when(repository.updateWorkEntity(id: expected.id, executed: any)).thenAnswer((_) async => Right(expected));
to be able to make my mock return a object for my test, by using "any" in the place of the "DateTime.now()", but I get this error:
Invalid argument(s): The "any" argument matcher is used outside of
method stubbing (via when) or verification (via verify or
untilCalled). This is invalid, and results in bad behavior during
the next stubbing or verification.
So I guess I can not use any here, but then how do I get my mock to return an object when I do not control one of the input parameters?
Thank you
Søren
Use executed: anyNamed('executed') instead of executed: any
When I run flutter pub pub run intl_translation:extract_to_arb --output-dir=lib/l10n lib/localizations.dart, the generator skips over all Intl.message files that only include a string, printing:
Skipping invalid Intl.message invocation
<Intl.message("MESSAGE")>
reason: The 'args' argument for Intl.message must be specified for messages with parameters. Consider using rewrite_intl_messages.dart
from lib/main.dart line: 125, column: 9
The doc for the internationalization package says The name and args parameters must match the name (or ClassName_methodName) and arguments list of the function respectively. For messages without parameters, both of these can be omitted. But it seems to me that, in this case, my message is without parameters!
Am I misunderstanding what Dart devs mean by parameters?
Move it out of the constructor into a separate function. You can call the function from the constructor, but it has to be a single message alone in a function.
The reason is to support messages with parameters. The translation gets generated, at least conceptually, as a separate function. So we have
foo(String name) => Intl.message('Hello $name', name: 'foo', args: [name]);
in a deferred library fr_FR somewhere
foo(String name) => 'Bonjour $name'
and the implementation of Intl.message is conceptually
currentLanguage.lookup('foo').call(args)
So there can only be one message in a function because we're going to replace that function with something else. And it can't be a constructor because we can't just delegate to that.
What is the syntax for setting lwwreg register values in CRDT Map on server side in Riak? I tried a code like below which doesn't seem to be valid:
%% Obj is a map object to which we want to add/set a register "uname" with value
%% "ahmed"
riak_kv_crdt:update(Obj,<<"testing">>,{crdt_op,riak_dt_map,
{update,[{assign,<<"uname">>,<<"ahmed">>}]},undefined})
I get an error about the operation being invalid - I looked around in source code for riak_dt_map.erl but still can't figure out correct syntax:
> riak_kv_crdt:update(Obj,<<"testing">>,{crdt_op,riak_dt_map,{update,
[{assign,<<"uname">>,<<"ahmed">>}]},undefined}).
** exception error: no function clause matching
riak_dt_map:apply_ops([{assign,<<"uname">>,<<"ahmed">>}],
{<<"testing">>,1},
{[{<<"testing">>,1}],
.....
Will appreciate pointers on correct syntax.
Figured it out. The correct syntax is below - the key must be accompanied by the type of the field which is riak_dt_lwwreg in this case, and assign operation must be specified for register value - so, the syntax becomes:
riak_kv_crdt:update(Obj,<<"testing">>,{crdt_op,riak_dt_map,{update,
[{update,{<<"uname">>,riak_dt_lwwreg},{assign,<<"ahmed">>}}]},undefined})
I am attempting to use the Redis TYPE command inside a Lua script (executed via EVAL)
local key_type = redis.call("TYPE", key)
According to the Redis documentation, this should return a string of "none", "zset" etc.
However the type of the returned value is a lua table. Comparing the value to a string always returns false.
I've managed to get around the problem by changing the call to
local key_type = redis.call("TYPE", key)["ok"]
This value is indeed a string and does work in string comparison commands. I am worried that this is a bug in my particular version of Redis and it will break in future versions when I upgrade.
Does anyone know if this is expected behaviour, or a bug?
The TYPE command returns a status reply (a.k.a simple string), e.g "+list\r\n".
On Redis scripting side, call is implemented by luaRedisCallCommand which performs the real Redis command behind the scenes.
Once successfully executed, this function converts the command result with redisProtocolToLuaType.
When a status reply is encountered, this function creates a Lua table with "ok" as key, and the status reply as value (see redisProtocolToLuaType_Status). So:
there is no bug,
this is why redis.call("TYPE", key) is a table (and thus you need to get the value for the "ok" key as you did, to get key's type as a string).
Note: when you directly return the table, Redis takes care to get the value associated to the "ok" key, and returns it as a status reply, e.g:
> EVAL 'return redis.call("TYPE", "foo")'
set
See this code section for more details.