how to get values from a const object? - dart

I created a const object at app.config.dart with the following code:
const configObj = const {
'webServer': const {
'appBaseHref' : "/"
},
'auth0': const {
'apiKey': "foo",
'domain': "bar",
'callbackUrl': "callback"
}
};
now in my main dart file I import the app.config.dart and I try to get the values there and now idea how to do that. configObj.auth0.apiKey produces the error EXCEPTION: Class 'ImmutableMap' has no instance getter 'auth0'.
so how do I do this ?
thanks!

Dart doesn't support to access map entries with .
It should be:
configObj['auth0']['apiKey'];
Alternatively you can create classes for your configuration like
class WebServerConfig {
final String appBaseHref;
const WebServerConfig(this.appBaseHref);
}
class Auth0Config {
final String apiKey;
final String domain;
final String callbackUrl;
const Auth0(this.apiKey, this.domain, this.callbackUrl);
}
class MyConfig {
final WebServerConfig webServer;
final Auth0Config auth0;
const MyConfig(this.webServer, this.auth0);
}
const configObj = const MyConfig(
const WebServerConfig("/"),
const Auth0Config(
"foo",
"bar",
"callback"
)
);
This way you also get proper auto-completion when you access the config properties and can use the simple . notation to access properties.

Related

Error when using argument matcher in mocking methods in dart null safety

I am getting the following error message when using argument matcher, any, when mocking a method in dart tests using mockito in a null safe dart code base.
What steps need to be taken to fix this issue
error:
The argument type 'Null' can't be assigned to the parameter type 'int'.
Test code can be found here:
class MockNumberTriviaRepository extends Mock implements NumberTriviaRespository {}
void main() {
late GetConcreteNumberTrivia usecase;
late MockNumberTriviaRepository mockNumberTriviaRepository;
setUp(() {
mockNumberTriviaRepository = MockNumberTriviaRepository();
usecase = GetConcreteNumberTrivia(mockNumberTriviaRepository);
});
const tNumber = 1;
const tNumberTrivia = NumberTrivia(number: tNumber, text: "test");
test('should get trivia for the number from repository', () async {
//arrange
when(mockNumberTriviaRepository.getConcreteNumberTrivia(any)).thenAnswer((_) async => const Right(tNumberTrivia));
//act
final result = await usecase.execute(tNumber);
//assert
// UseCase should simply return whatever was returned from the Repository
expect(result, const Right(tNumberTrivia));
// Verify that the method has been called on the Repository
verify(mockNumberTriviaRepository.getConcreteNumberTrivia(tNumber));
verifyNoMoreInteractions(mockNumberTriviaRepository);
});
}
Implementation code can be found here:
abstract class NumberTriviaRespository {
Future<Either<Failure, NumberTrivia>> getConcreteNumberTrivia(int number);
Future<Either<Failure, NumberTrivia>> getRandomNumberTrivia();
}
abstract class Failure extends Equatable {
const Failure([List properties = const <dynamic>[]]);
}
class GetConcreteNumberTrivia {
final NumberTriviaRespository respository;
const GetConcreteNumberTrivia(this.respository);
Future<Either<Failure, NumberTrivia>> execute(int number) async {
return await respository.getConcreteNumberTrivia(number);
}
}
class NumberTrivia extends Equatable {
final String text;
final int number;
const NumberTrivia({required this.text, required this.number});
#override
List<Object?> get props => [text, number];
}
Mockito has issues with Dart Null-safety. Please see https://github.com/dart-lang/mockito/blob/master/NULL_SAFETY_README.md.
You can override the implementation of your mock class to support a null argument by following the recipes on the link above:
class MockNumberTriviaRepository extends Mock
implements NumberTriviaRespository {
#override
Future<Either<Failure, NumberTrivia>> getConcreteNumberTrivia(int? number) =>
super.noSuchMethod(Invocation.method(#getConcreteNumberTrivia, [number]),
returnValue: Future.value(
Right<Failure, NumberTrivia>(NumberTrivia(text: "", number: 1))));
}

Dart HashMap initial value

I have a final HashMap in a class, How can I have a default value for it?
class RoomsState {
final HashMap<int, int> myMap;
RoomsState({
this.myMap= const {}
});
}
as const {} is a Map and not HashMap I cannot do it, Also HashMap is not a const constructor
Not sure if this is the only way to do it, but it is an option:
import 'dart:collection';
class RoomsState {
final HashMap<int, int> myMap;
RoomsState({
HashMap<int, int>? myMap
}) : this.myMap = myMap ?? HashMap();
}
The myMap parameter are here nullable since we are using the null value to identify if we got any argument.
You could expect a Map in your constructor and then convert it to a HashMap in an initializer.
class RoomsState {
final HashMap<int, int> myMap;
RoomsState({
Map<int, int> map = const {},
}) : myMap = HashMap.from(map);
}
HashMap has the construtor of that creates a HashMap that contains all key/value pairs of other. Check this for reference.
Example:
HashMap<String, String> englishToFrench = HashMap.of({
"go": "aller",
"buy": "acheter",
"sleep": "dormir",
});
Usage example:
void main() {
print(englishToFrench["go"]);
}
Output:
aller

Difference between const constructor and cost?

I have the following code snippet:
class ImmutablePoint {
final double x, y;
const ImmutablePoint(this.x, this.y);
}
void main() {
var i = const ImmutablePoint(4,6);
print(i.x);
}
As you can see, a const constructor is defined in the class. However, what is the difference between const and const constructor?
What is the difference when I change from var i = const ImmutablePoint(4,6); to var i = ImmutablePoint(4,6);?
The point is, sometimes I see in flutter example const Text("FFF"), although a const constructor is already defined for the text.
A class with a const constructor only allows you to create const instances of that class, but it does not make all instances const.
That is controlled at the constructor invocation site - the const constructor is only used within a const context. A const context is basically inferred by any precedingconst keyword, the following all would use the const constructor:
var foo = const ImmutablePoint(1,2);
const foo = ImmutablePoint(1,2);
var foos = const [ImmutablePoint(1,2)];
But the following would not, as it is not in a const context:
var foo = ImmutablePoint(1,2);

Dart - Circular dependency while initializing static field

I'm new to dart and just encountered an issue which I don't understand yet.
I wrote this class:
class Currency {
final String symbol;
final String name;
// constants for all available Currencies
static const Currency EURO = const Currency._euro();
static const Currency POUND = const Currency._pound();
static const Currency DOLLAR = const Currency._dollar();
// All available currencies as a list
static const List<Currency> CURRENCIES = const [
EURO,
POUND,
DOLLAR,
];
// Default constructor
Currency(this.symbol, this.name);
// Named constructors
const Currency._euro() : this('€', 'Euro');
const Currency._pound() : this('£', 'British Pound');
const Currency._dollar() : this('\$', 'US Dollar');
// toString()
#override
String toString() => '$symbol ($name)';
}
When using this class, for example with the statement below I get a "Circular dependency while initializing static field"-error.
Currency currency = Currency.EURO;
Could anyone explain to me what is going on?
I can't reproduce your error, but a const was missing before the constructor you redirect others to
const Currency(this.symbol, this.name);

is possible have a configuration file in DART?

I have this JavaScript class:
'use strict;'
/* global conf */
var properties = {
'PROPERTIES': {
'CHANNEL': 'sport',
'VIEW_ELEMENTS': {
'LOADER_CLASS': '.loader',
'SPLASH_CLASS': '.splash'
}
}
};
In JavaScript I can use these properties: properties.PROPERTIES.CHANNEL
Is it possible to convert this to DART? Is there a best practise to do that?
There are different way.
You could just create a map
my_config.dart
const Map properties = const {
'CHANNEL': 'sport',
'VIEW_ELEMENTS': const {
'LOADER_CLASS': '.loader',
'SPLASH_CLASS': '.splash'
}
}
then use it like
main.dart
import 'my_config.dart';
main() {
print(properties['VIEW_ELEMENTS']['SPLASH_CLASS']);
}
or you can use classes to get proper autocompletion and type checking
my_config.dart
const properties = const Properties('sport', const ViewElements('.loader', '.splash'));
class Properties {
final String channel;
final ViewElements viewElements;
const Properties(this.channel, this.viewElements;
}
class ViewElements {
final String loaderClass;
final String splashClass;
const ViewElements(this.loaderClass, this.splashClass);
}
main.dart
import 'my_config.dart';
main() {
print(properties.viewElements.splashClass);
}
Following up on the above answer using classes, it may be convenient to implement static variables, the downside is that it still must be compiled/rebuilt.
class CONFIG {
static final String BUILD = "Release";
static final String DEPLOYMENT = "None";
}
This can be used from a separate class after importing via:
var xyz = CONFIG.BUILD;

Resources