Advertisement
Guest User

Untitled

a guest
Oct 20th, 2019
102
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.47 KB | None | 0 0
  1. class BuiltRef<T> {
  2. /// Holds the ref, can also be null
  3. final T value;
  4.  
  5. /// Whether this was constructed using [BuiltRef.undefined]
  6. final bool isUndefined;
  7.  
  8. /// Create a new reference to [value]
  9. const BuiltRef(this.value) : isUndefined = false;
  10.  
  11. /// Used as the default value in parameter definition
  12. const BuiltRef.undefined()
  13. : value = null,
  14. isUndefined = true;
  15.  
  16. @override
  17. int get hashCode => value.hashCode;
  18. @override
  19. operator ==(Object other) => other is BuiltRef
  20. ? value == other.value && isUndefined == other.isUndefined
  21. : false;
  22.  
  23. @override
  24. String toString() => value.toString();
  25. }
  26.  
  27. abstract class MyValue {
  28. /// String that can be null but also has a default
  29. String get nullableStringWithDefault => 'default value';
  30.  
  31. /// Must have an int value
  32. int get mustHaveInt;
  33.  
  34. MyValue._() {
  35. if ((nullableStringWithDefault?.length ?? 0) > 50) {
  36. throw Exception('String is too big');
  37. }
  38. print('validation checks pass!');
  39. }
  40.  
  41. factory MyValue([Function(MyValueBuilder) updates]) = MyValueImpl;
  42. }
  43.  
  44. class MyValueImpl extends MyValue {
  45. BuiltRef<String> _nullableStringWithDefault;
  46.  
  47. String get nullableStringWithDefault =>
  48. (_nullableStringWithDefault ??= BuiltRef(super.nullableStringWithDefault))
  49. .value;
  50.  
  51. BuiltRef<int> _mustHaveInt;
  52.  
  53. int get mustHaveInt => _mustHaveInt.value;
  54.  
  55. MyValueImpl._withBuiltRef({
  56. BuiltRef<String> nullableStringWithDefault = const BuiltRef.undefined(),
  57. BuiltRef<int> mustHaveInt,
  58. }) : _mustHaveInt = mustHaveInt,
  59. _nullableStringWithDefault =
  60. nullableStringWithDefault?.isUndefined ?? false
  61. ? null
  62. : nullableStringWithDefault,
  63. super._() {
  64. /// Null checks
  65. if (mustHaveInt?.value == null) {
  66. throw ArgumentError.notNull('mustHaveInt');
  67. }
  68. print('null checks pass!');
  69. }
  70.  
  71. /// Existing code that uses this constructor should work as expected
  72. /// Here nullableStringWithDefault can be set to `null` explicitly
  73. MyValueImpl._({
  74. String nullableStringWithDefault,
  75. int mustHaveInt,
  76. }) : this._withBuiltRef(
  77. nullableStringWithDefault: BuiltRef(nullableStringWithDefault),
  78. mustHaveInt: BuiltRef(mustHaveInt),
  79. );
  80.  
  81. /// Existing code using this factory will allow default values as well as setting to `null` explicitly
  82. factory MyValueImpl([Function(MyValueBuilder) updates]) =>
  83. (MyValueBuilder()..update(updates)).build();
  84. }
  85.  
  86. class MyValueBuilder {
  87. MyValueImpl _$v;
  88.  
  89. /// Initially, the builder doesn't initialize any fields so this will be null
  90. BuiltRef<String> _nullableStringWithDefault;
  91.  
  92. String get nullableStringWithDefault =>
  93. _$this._nullableStringWithDefault.value;
  94.  
  95. set nullableStringWithDefault(String nullableStringWithDefault) {
  96. /// This is a nullable field, we don't care what the value is
  97. _$this._nullableStringWithDefault = BuiltRef(nullableStringWithDefault);
  98. }
  99.  
  100. BuiltRef<int> _mustHaveInt;
  101.  
  102. int get mustHaveInt => _$this._mustHaveInt.value;
  103. set mustHaveInt(int mustHaveInt) {
  104. /// For non-nullable fields, throw optionally to provide a better stack trace
  105. _$this._mustHaveInt =
  106. BuiltRef(mustHaveInt ?? (throw ArgumentError.notNull('mustHaveInt')));
  107.  
  108. /// Or just set the value and let the constructor of MyValueImpl handle null values
  109. // _$this._mustHaveInt = BuiltRef(mustHaveInt);
  110. }
  111.  
  112. MyValueBuilder get _$this {
  113. if (_$v != null) {
  114. _nullableStringWithDefault =
  115. BuiltRef(_$v.nullableStringWithDefault) ?? BuiltRef.undefined();
  116. _mustHaveInt = BuiltRef(_$v.mustHaveInt);
  117. _$v = null;
  118. }
  119.  
  120. return this;
  121. }
  122.  
  123. void replace(MyValue value) => _$v = value;
  124.  
  125. void update([Function(MyValueBuilder) updates]) => updates?.call(_$this);
  126.  
  127. MyValue build() {
  128. return _$v ??
  129. MyValueImpl._withBuiltRef(
  130. nullableStringWithDefault:
  131. _nullableStringWithDefault ?? const BuiltRef.undefined(),
  132. mustHaveInt: _mustHaveInt,
  133. );
  134. }
  135. }
  136.  
  137. void main([List<String> args]) {
  138. useCase("When default values are used", () {
  139. final defaultValue = MyValue((b) => b.mustHaveInt = 1);
  140. print(defaultValue.nullableStringWithDefault);
  141. });
  142.  
  143. useCase("When default values are ignored (custom value is used)", () {
  144. final customValue = MyValue((b) => b
  145. ..nullableStringWithDefault = "custom value"
  146. ..mustHaveInt = 2);
  147. print(customValue.nullableStringWithDefault);
  148. });
  149.  
  150. useCase("When default values are ignored and explicitly set to null", () {
  151. final explicitNullValue = MyValue((b) => b
  152. ..nullableStringWithDefault = null
  153. ..mustHaveInt = 3);
  154. print(explicitNullValue.nullableStringWithDefault);
  155. });
  156.  
  157. useCase("When default values are ignored and validation fails", () {
  158. try {
  159. MyValue((b) => b
  160. ..nullableStringWithDefault =
  161. "custom value tooooooooooooooooooooooooooooooooooooooooooooooooooooo big"
  162. ..mustHaveInt = 4);
  163. } catch (e) {
  164. print('validation checks failed!');
  165. }
  166. });
  167.  
  168. useCase("When default values are used but null checks fail", () {
  169. try {
  170. MyValue();
  171. } catch (e) {
  172. print('null checks failed');
  173. }
  174. });
  175.  
  176. useCase("When non-nullables are explicitly set to null", () {
  177. try {
  178. MyValueBuilder()
  179. ..update((b) => b.mustHaveInt = null)
  180. ..build();
  181. } catch (e) {
  182. print('Builder fails to build');
  183. }
  184. });
  185. }
  186.  
  187. void useCase(String name, Function function) {
  188. print("");
  189. print("".padRight(40, "#"));
  190. print(name);
  191. function();
  192. print("".padRight(40, "#"));
  193. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement