generic_reader 0.4.0 copy "generic_reader: ^0.4.0" to clipboard
generic_reader: ^0.4.0 copied to clipboard

Extension providing methods for the systematic reading of enums, constant lists, maps, sets, and generic compile-time constant expressions.

example/README.md

Generic Reader - Example #

Dart

Retrieving Constants with Parameterized Type #

The file player_example.dart demonstrates how to use the library generic_reader to read the value of a constant with parameterized type from a static representation of a compile-time constant expression. The program also shows how to register Decoder functions for the types Column and SqliteType.

The constant values that are going to be read are the fields of the const class Player:

Click to show player.dart.
import 'package:test_types/test_types.dart';

/// Class modelling a player.
class Player {
  const Player();

  /// Column name
  final columnName = 'Player';

  /// Column storing player id.
  final id = const Column<int>(defaultValue: 1, name: 'id');

  /// Column storing first name of player.
  final firstName = const Column<String>(
    defaultValue: 'Thomas',
    name: 'FirstName',
  );

  /// List of sponsors
  final List<Sponsor> sponsors = const [
    Sponsor('Johnson\'s'),
    Sponsor('Smith Brothers'),
  ];

  /// Test unregistered type.
  final unregistered = const UnRegisteredTestType();

  /// Test [Set<int>].
  final Set<int> primeNumbers = const {1, 3, 5, 7, 11, 13};

  /// Test enum
  final Greek greek = Greek.alpha;

  /// Test map
  final map = const <String, dynamic>{'one': 1, 'two': 2.0};

  /// Test map with enum entry
  final mapWithEnumEntry = const <String, dynamic>{
    'one': 1,
    'two': 2.0,
    'enum': Greek.alpha
  };

  /// Test list
  final list = const <List<int>>[
    [0, 1],
    [10, 11]
  ];
}

In the simple example below, the function initializeLibraryReaderForDirectory provided by source_gen_test is used to load the source code and initialize objects of type LibraryReader.

In a standard setting this task is delegated to a builder that reads a builder configuration and loads the relevant assets.

Click to show player_example.dart.
import 'package:ansicolor/ansicolor.dart';
import 'package:exception_templates/exception_templates.dart';
import 'package:generic_reader/generic_reader.dart';
import 'package:source_gen/source_gen.dart' show ConstantReader;
import 'package:source_gen_test/source_gen_test.dart';
import 'package:test_types/test_types.dart';

/// To run this program navigate to the root folder
/// in your local copy the package `generic_reader` and
/// use the command:
///
/// # dart example/bin/player_example.dart

/// Demonstrates how to use [GenericReader] to read constants
/// with parameterized type from a static representation
/// of a compile-time constant expression
/// represented by a [ConstantReader].
Future<void> main() async {
  /// Reading libraries.
  print('Reading player.dart ...');
  final playerLib = await initializeLibraryReaderForDirectory(
    'example/src',
    'player.dart',
  );
  print('Done reading player.dart');

  // ConstantReader representing field 'columnName'.
  final columnNameCR =
      ConstantReader(playerLib.classes.first.fields[0].computeConstantValue());

  final idCR =
      ConstantReader(playerLib.classes.first.fields[1].computeConstantValue());

  // ConstantReade representing field 'firstName'.
  final firstNameCR =
      ConstantReader(playerLib.classes.first.fields[2].computeConstantValue());

  final sponsorsCR =
      ConstantReader(playerLib.classes.first.fields[3].computeConstantValue());

  final greekCR =
      ConstantReader(playerLib.classes.first.fields[6].computeConstantValue());

  final mapCR =
      ConstantReader(playerLib.classes.first.fields[7].computeConstantValue());

  final mapWithEnumEntryCR =
      ConstantReader(playerLib.classes.first.fields[8].computeConstantValue());

  final listCR =
      ConstantReader(playerLib.classes.first.fields[9].computeConstantValue());

  // Adding a decoder for constants of type [Column].
  GenericReader.addDecoder<Column>((cr) {
    final name = cr.read('name').get<String>();

    if (cr.holdsA<Column<int>>()) {
      final defaultValue = cr.read('defaultValue').get<int>();
      return Column<int>(defaultValue: defaultValue, name: name);
    }
    if (cr.holdsA<Column<bool>>()) {
      final defaultValue = cr.read('defaultValue').get<bool>();
      return Column<bool>(defaultValue: defaultValue, name: name);
    }
    if (cr.holdsA<Column<String>>()) {
      final defaultValue = cr.read('defaultValue').get<String>();
      return Column<String>(defaultValue: defaultValue, name: name);
    }
    if (cr.holdsA<Column<double>>()) {
      final defaultValue = cr.read('defaultValue').get<double>();
      return Column<double>(defaultValue: defaultValue, name: name);
    }
    throw ErrorOf<Decoder<Column>>(
        message: 'Error reading constant expression.',
        expectedState: 'An instance of ConstantReader holding a '
            'constant of type `Column`.');
  });

  final green = AnsiPen()..green(bold: true);

  // Retrieve an instance of [String].
  final columnName = columnNameCR.get<String>();
  print(green('Retrieving a String:'));
  print('columnName = \'$columnName\'');
  print('');
  // Prints:
  // Retrieving a [String]
  // columnName = 'Player'

  // Retrieve an instance of [Column<Text>].
  final columnFirstName = firstNameCR.get<Column>();
  print(green('Retrieving a Column<Text>:'));
  print(columnFirstName);
  // Prints:
  // Retrieving a [Column<Text>]:
  // Column<Text>(
  //   defaultValue: Text('Thomas')
  // )

  // Adding a decoder function for type [Sponsor].
  GenericReader.addDecoder<Sponsor>(
      (cr) => Sponsor(cr.read('name').stringValue));

  final sponsors = sponsorsCR.getList<Sponsor>();

  print('');
  print(green('Retrieving a List<Sponsor>:'));
  print(sponsors);
  // Prints:
  // Retrieving a [List<Sponsor>]:
  // [Sponsor: Johnson's, Sponsor: Smith Brothers]

  final id = idCR.get<Column>();
  print('');
  print(green('Retrieving a Column<Integer>:'));
  print(id);
  // Prints:
  // Retrieving a [Column<Integer>]:
  // Column<Integer>(
  // )

  final greek = greekCR.get<Greek>();
  print('');
  print(green('Retrieving an instance of the '
      'enumeration: Greek{alpha, beta}.'));
  print(greek);
  // Prints:
  // 'Retrieving an instance of the enumeration: Greek{alpha, beta}.'
  // Greek.alpha

  final map = mapCR.getMap<String, dynamic>();
  print('');
  print(green('Retrieving a Map<String, dynamic>:'));
  print(map);
  // Prints:
  // 'Retrieving a Map<String, dynamic>:'
  // {one: 1, two: 2.0}

  GenericReader.addDecoder<Greek>((cr) => cr.get<Greek>());
  final mapWithEnumEntry = mapWithEnumEntryCR.getMap<String, dynamic>();
  print('');
  print(green('Retrieving a Map<String, dynamic>:'));
  print(mapWithEnumEntry);
  // Prints:
  // 'Retrieving a Map<String, dynamic>:'
  // {one: 1, two: 2.0, enum: Greek.alpha}

  // Retrieving a nested list.
  // Add a specific decoder for the inner type.
  GenericReader.addDecoder<List<int>>((cr) => cr.getList<int>());

  final list = listCR.getList<List<int>>();
  print(green('\nRetrieving a List<List<int>>'));
  print(list);
}

Retrieving Constants with Dynamic Type #

The example in the section above demonstrates how to retrieve constants with a known parameterized type.

The program presented below shows how to proceed if the constant has a dynamic type parameter. Note: The actual data-type must be either a bool, double, int, num, String, Type, Symbol or a type with a registered decoder.

Consider the following generic class that wraps a value of type T:

/// Wraps a variable of type [T].
class Wrapper<T> {
  const Wrapper(this.value);

  /// Value of type [T].
  final T value;

  @override
  String toString() => 'Wrapper<$T>(value: $value)';
}

The type argument T can assume any data-type and it is impractical to handle all available types manually in the decoder function of Wrapper.

Instead, one can use the method get<dynamic>(). This signals to the reader to match the static type of the ConstantReader instance to a registered data-type. If a match is found get<dynamic>() returns a constant with the appropriate value, otherwise an error is thrown.

The program below retrieves the constant wrapper defined in [wrapper_instance.dart]. Note the use of the method get<dynamic>() when defining the Decoder function for the data-type Wrapper.

Click to show wrapper_example.dart.
import 'package:analyzer/dart/element/element.dart';
import 'package:ansicolor/ansicolor.dart';
import 'package:generic_reader/generic_reader.dart';
import 'package:source_gen/source_gen.dart'; // show ConstantReader;
import 'package:source_gen_test/src/init_library_reader.dart';

import 'package:test_types/test_types.dart';

/// To run this program navigate to the root folder
/// in your local copy the package `generic_reader` and
/// use the command:
///
/// # dart example/bin/wrapped_int_example.dart

/// Demonstrates how to use `GenericReader` to read constants
/// with parameterized type from a static representation
/// of a compile-time constant expression
/// represented by a `ConstantReader`.
Future<void> main() async {
  /// Reading libraries.
  final wrappedIntLib = await initializeLibraryReaderForDirectory(
    'example/src',
    'wrapper_instance.dart',
  );

  ConstantReader? wrapperCR;

  for (var element in wrappedIntLib.allElements) {
    if (element is TopLevelVariableElement) {
      if (element.name == 'wrapper') {
        wrapperCR = ConstantReader(element.computeConstantValue());
      }
    }
  }

  final green = AnsiPen()..green(bold: true);

  // Adding a decoder function for type [Wrapper].
  GenericReader.addDecoder<Wrapper>((ConstantReader cr) {
    return Wrapper(cr.read('value').get<dynamic>());
  });

  print('');
  print(green('Retrieving a Wrapper<dynamic>:'));
  if (wrapperCR == null) {
    print('Could not read constant of type Wrapper<dynamic>');
    return;
  }
  final wrapper = wrapperCR.get<Wrapper>();
  print(wrapper);
  print(wrapper.value.runtimeType);
  // Prints:
  //
  // Retrieving a [Wrapper<dynamic>]:
  // Wrapper<dynamic>(value: 297)
  // int
}

Features and bugs #

Please file feature requests and bugs at the issue tracker.

5
likes
130
pub points
34%
popularity

Publisher

verified publishersimphotonics.com

Extension providing methods for the systematic reading of enums, constant lists, maps, sets, and generic compile-time constant expressions.

Repository (GitHub)
View/report issues

Documentation

API reference

License

BSD-3-Clause (LICENSE)

Dependencies

analyzer, exception_templates, source_gen

More

Packages that depend on generic_reader