Skip to content

Commit 3be4b33

Browse files
committed
Merge branch 'master' into big_nnbd_refactoring
# Conflicts: # pubspec.yaml # test/src/pick_test.dart
2 parents 739ec87 + 72aaca5 commit 3be4b33

7 files changed

Lines changed: 88 additions & 27 deletions

File tree

CHANGELOG.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,21 @@
1+
## 0.6.0-nullsafety.1
2+
3+
- New `asXyzOrThrow()` methods as shorthand for `.required().asXyz()` featuring better error messages
4+
- `asBoolOrThrow()`
5+
- `asDateTimeOrThrow()`
6+
- `asDoubleOrThrow()`
7+
- `asIntOrThrow()`
8+
- `letOrThrow()`
9+
- `asListOrThrow()`
10+
- `asMapOrThrow()`
11+
- `asStringOrThrow()`
12+
- New `Pick.isAbsent` getter to check if a value is absent or `null` [#24](https://github.com/passsy/deep_pick/pull/24). Absent could mean
13+
1. Accessing a key which doesn't exist in a `Map`
14+
2. Reading the value from `List` when the index is greater than the length
15+
3. Trying to access a key in a `Map` but the found data a `Object` which isn't a Map
16+
- The String `"true"` and `"false"` are now parsed as boolean
17+
- More nnbd refactoring
18+
119
## 0.6.0-nullsafety.0
220

321
- Migrate to nullsafety (required Dart >=2.12)

example/deep_pick_example.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ void main() {
8181

8282
// access value out of range
8383
final puma = pick(json, 'shoes', 1);
84-
print(puma.isAbsent()); // true;
84+
print(puma.isAbsent); // true;
8585
print(puma.value); // null
8686
}
8787

@@ -111,7 +111,7 @@ class Shoe {
111111
tags: pick('tags').asListOrEmpty((it) => it.asString()),
112112
price: () {
113113
// when server doesn't send the price field the shoe is not available
114-
if (pricePick.isAbsent()) return 'Not for sale';
114+
if (pricePick.isAbsent) return 'Not for sale';
115115
return pricePick.asStringOrNull() ?? 'Price available soon';
116116
}(),
117117
);

lib/src/pick.dart

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -108,15 +108,15 @@ class Pick with PickLocation, PickContext<Pick> {
108108
/// - Trying to access a key in a [Map] but the found data structure is a [List]
109109
///
110110
/// ```
111-
/// pick({"a": null}, "a").isAbsent(); // false
112-
/// pick({"a": null}, "b").isAbsent(); // true
111+
/// pick({"a": null}, "a").isAbsent; // false
112+
/// pick({"a": null}, "b").isAbsent; // true
113113
///
114-
/// pick([null], 0).isAbsent(); // false
115-
/// pick([], 2).isAbsent(); // true
114+
/// pick([null], 0).isAbsent; // false
115+
/// pick([], 2).isAbsent; // true
116116
///
117-
/// pick([], "a").isAbsent(); // true
117+
/// pick([], "a").isAbsent; // true
118118
/// ```
119-
bool isAbsent() => missingValueAtIndex != null;
119+
bool get isAbsent => missingValueAtIndex != null;
120120

121121
@override
122122
List<dynamic> path;
@@ -166,7 +166,7 @@ class Pick with PickLocation, PickContext<Pick> {
166166
final more = fromContext(requiredPickErrorHintKey).value as String?;
167167
final moreSegment = more == null ? '' : ' $more';
168168
throw PickException('required value at location ${location()} '
169-
'is ${isAbsent() ? 'absent' : 'null'}.$moreSegment');
169+
'is ${isAbsent ? 'absent' : 'null'}.$moreSegment');
170170
}
171171
return RequiredPick(value, path: path, context: _context);
172172
}

lib/src/pick_double.dart

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,41 @@ extension DoublePick on RequiredPick {
1010
return value.toDouble();
1111
}
1212
if (value is String) {
13-
final parsed = double.tryParse(value);
13+
var parsed = double.tryParse(value);
1414
if (parsed != null) {
1515
return parsed;
1616
}
17+
// remove all spaces
18+
final prepared = value.replaceAll(' ', '');
19+
20+
if (prepared.contains(',') && !prepared.contains('.')) {
21+
// Germans use , instead of . as decimal separator
22+
// 12,56 -> 12.56
23+
parsed = double.tryParse(prepared.replaceAll(',', '.'));
24+
if (parsed != null) {
25+
return parsed;
26+
}
27+
}
28+
29+
// handle digit group separators
30+
final firstDot = prepared.indexOf('.');
31+
final firstComma = prepared.indexOf(',');
32+
33+
if (firstDot <= firstComma) {
34+
// the germans again
35+
// 10.000,00
36+
parsed =
37+
double.tryParse(prepared.replaceAll('.', '').replaceAll(',', '.'));
38+
if (parsed != null) {
39+
return parsed;
40+
}
41+
} else {
42+
// 10,000.00
43+
parsed = double.tryParse(prepared.replaceAll(',', ''));
44+
if (parsed != null) {
45+
return parsed;
46+
}
47+
}
1748
}
1849
throw PickException('value $value of type ${value.runtimeType} '
1950
'at location ${location()} can not be parsed as double');

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: deep_pick
22
description: Simplifies manual JSON parsing with a type-safe API. No dynamic, no manual casting. Flexible inputs types, fixed output types. Useful parsing error messages
3-
version: 0.6.0-nullsafety.0
3+
version: 0.6.0-nullsafety.1
44
homepage: https://github.com/passsy/deep_pick
55

66
environment:

test/src/pick_double_test.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,17 @@ void main() {
2424
expect(pick('12345.01').asDoubleOrThrow(), 12345.01);
2525
});
2626

27+
test('parse german doubles', () {
28+
expect(pick('1,0').asDoubleOrThrow(), 1.0);
29+
expect(pick('12345,01').asDoubleOrThrow(), 12345.01);
30+
});
31+
32+
test('parse double with separators', () {
33+
expect(pick('12,345.01').asDoubleOrThrow(), 12345.01);
34+
expect(pick('12 345,01').asDoubleOrThrow(), 12345.01);
35+
expect(pick('12.345,01').asDoubleOrThrow(), 12345.01);
36+
});
37+
2738
test('null throws', () {
2839
expect(
2940
() => nullPick().asDoubleOrThrow(),

test/src/pick_test.dart

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,10 @@ void main() {
5555

5656
test('toString() prints value and path', () {
5757
expect(
58-
// ignore: deprecated_member_use_from_same_package
59-
Pick('a', path: ['b', 0]).toString(),
60-
'Pick(value=a, path=[b, 0])');
58+
// ignore: deprecated_member_use_from_same_package
59+
Pick('a', path: ['b', 0]).toString(),
60+
'Pick(value=a, path=[b, 0])',
61+
);
6162
});
6263

6364
test(
@@ -105,32 +106,32 @@ void main() {
105106
expect(level2Pick.path, [0, 'name']);
106107
});
107108

108-
group('isAbsent()', () {
109+
group('isAbsent', () {
109110
test('is not absent because value', () {
110111
final p = pick('a');
111112
expect(p.value, isNotNull);
112-
expect(p.isAbsent(), isFalse);
113+
expect(p.isAbsent, isFalse);
113114
expect(p.missingValueAtIndex, null);
114115
});
115116

116117
test('is not absent but null', () {
117118
final p = pick(null);
118119
expect(p.value, isNull);
119-
expect(p.isAbsent(), isFalse);
120+
expect(p.isAbsent, isFalse);
120121
expect(p.missingValueAtIndex, null);
121122
});
122123

123124
test('is not absent but null further down', () {
124125
final p = pick({'a': null}, 'a');
125126
expect(p.value, isNull);
126-
expect(p.isAbsent(), isFalse);
127+
expect(p.isAbsent, isFalse);
127128
expect(p.missingValueAtIndex, null);
128129
});
129130

130131
test('is not absent, not null', () {
131132
final p = pick({'a', 1}, 'b');
132133
expect(p.value, isNull);
133-
expect(p.isAbsent(), isTrue);
134+
expect(p.isAbsent, isTrue);
134135
expect(p.missingValueAtIndex, 0);
135136
});
136137

@@ -140,7 +141,7 @@ void main() {
140141
};
141142
final p = pick(json, 'a', 'x' /*absent*/);
142143
expect(p.value, isNull);
143-
expect(p.isAbsent(), isTrue);
144+
expect(p.isAbsent, isTrue);
144145
expect(p.missingValueAtIndex, 1);
145146
});
146147
});
@@ -153,39 +154,39 @@ void main() {
153154
{'name': 'Daenerys Targaryen'},
154155
];
155156
expect(pick(data, 10).value, isNull);
156-
expect(pick(data, 10).isAbsent(), true);
157+
expect(pick(data, 10).isAbsent, true);
157158
});
158159

159160
test('unknown property in map returns null', () {
160161
final data = {'name': 'John Snow'};
161162
expect(pick(data, 'birthday').value, isNull);
162-
expect(pick(data, 'birthday').isAbsent(), true);
163+
expect(pick(data, 'birthday').isAbsent, true);
163164
});
164165

165166
test('documentation example Map', () {
166167
final pa = pick({'a': null}, 'a');
167168
expect(pa.value, isNull);
168-
expect(pa.isAbsent(), false);
169+
expect(pa.isAbsent, false);
169170

170171
final pb = pick({'a': null}, 'b');
171172
expect(pb.value, isNull);
172-
expect(pb.isAbsent(), true);
173+
expect(pb.isAbsent, true);
173174
});
174175

175176
test('documentation example List', () {
176177
final p0 = pick([null], 0);
177178
expect(p0.value, isNull);
178-
expect(p0.isAbsent(), false);
179+
expect(p0.isAbsent, false);
179180

180181
final p2 = pick([], 2);
181182
expect(p2.value, isNull);
182-
expect(p2.isAbsent(), true);
183+
expect(p2.isAbsent, true);
183184
});
184185

185186
test('Map key for list', () {
186187
final p = pick([], 'a');
187188
expect(p.value, isNull);
188-
expect(p.isAbsent(), true);
189+
expect(p.isAbsent, true);
189190
});
190191
});
191192

0 commit comments

Comments
 (0)