generic_reader

Last updated:

0 purchases

generic_reader Image
generic_reader Images
Add to Cart

Description:

generic reader

Generic Reader #

Introduction #
The premise of source code generation is that we can specify
(hopefully few) details and flesh out the rest of the classes, and methods during the build process.
Dart's static analyzer provides access to libraries, classes,
class fields, class methods, functions, variables, etc in the form of Elements.
Source code generation relies heavily on constants known at compile time.
Compile-time constant expressions are represented by a DartObject and
can be accessed by using the method computeConstantValue() (available for elements representing a variable).
For built-in types, DartObject has methods that allow reading the underlying constant object.
It is a more laborious task to read constant values of user defined data-types.
The package generic_reader includes extentions on
ConstantReader that simplify reading constants of type List, Set, Map, Enum
and provides a systematic way of reading arbitrary constants of known data-type.
Usage #
To use the package generic_reader the following steps are required:


Include generic_reader and source_gen as dependencies in your pubspec.yaml file.


Register a Decoder function for each user defined data-type T that is going to be read.
A decoder function has the signature T Function(ConstantReader constantReader). It reads the constant expression
represented by constantReader and returns a instance of T.
Note: The built-in types bool, double, int, String, Type, Symbol, and Dart enums do not require a decoder function.


Retrieve the compile-time constant values using the methods get<T>(), getList<T>(),
getSet<T>(), getMap<T>().


Process the retrieved compile-time constants and generate the required source code.


Decoder Functions #
The extension GenericReader provides a systematic method of retrieving constants of
arbitrary data-types by allowing users to register Decoder functions (for lack of a better a name).
Decoder functions can make use of other registered decoder functions enabling the retrieval of
complex generic data-structures.
Decoders functions know how to decode a specific data-type and have the following signature:
typedef T Decoder<T>(ConstantReader constantReader);
copied to clipboard
The input argument is of type ConstantReader, a wrapper around
DartObject,
and the function returns an object of type T.
It is required that the input argument constantReader represents an object of type T.
User defined types are often a composition of other types, as illustrated in the example below.
Click to show source-code.
enum Title{Mr, Mrs, Dr}

class Age {
const Age(this.age);
final int age;
bool get isAdult => age > 21;

@override
String toString() {
return 'age: $age';
}
}

class Name {
const Name({
required this.firstName,
required this.lastName,
this.middleName = '',
});
final String firstName;
final String lastName;
final String middleName;

@override
String toString() {
return '$firstName ${middleName == '' ? '' : middleName + ' ' }$lastName';
}
}

class User {
const User({
required this.name,
required this.id,
required this.age,
required this.title,
});
final Name name;
final Age age;
final int id;
final Title title;

@override
String toString() {
return 'user: $name\n'
' title: ${title}\n'
' id: $id\n'
' $age\n';
}
}

copied to clipboard

In order to retrieve a constant value of type User one has
to retrieve the constructor parameters of type int, Name, Title, and Age first.
The following shows how to define decoder functions for the types Age, Name, and User.
Note that each decoder knows the constructor parameter-names and parameter-types
of the class it handles. For example, the decoder for User knows that age has type Age and that the field-name is age.
import 'package:generic_reader/generic_reader.dart';
import 'package:source_gen/source_gen.dart' show ConstantReader;

import 'package:test_types/test_types.dart';

/// Defining decoder functions.
Age ageDecoder(ConstantReader constantReader) => Age(constantReader.read('age').intValue);

Name nameDecoder(ConstantReader constantReader) {
final firstName = constantReader.read('firstName').stringValue;
final lastName = constantReader.read('lastName').stringValue;
final middleName = constantReader.read('middleName').stringValue;
return Name(firstName: firstName, lastName: lastName, middleName: middleName);
};

User userDecoder(ConstantReader constantReader){
final id = constantReader.read('id').intValue;
final age = constantReader.read('age').get<Age>();
final name = constantReader.read('name').get<Name>();
final tile = constantReader.read('title').get<Title>();
return User(name: name, age: age, id: id, title: title);
};

// Registering decoders.
GenericReader.addDecoder<Age>(ageDecoder)
GenericReader.addDecoder<Name>(nameDecoder)
GenericReader.addDecoder<User>(userDecoder);

// Reading the library where an object of type User is defined.
// Retrieving the ConstantReader object representing an instance of User:
// constantReaderOfUser.

// Retrieving a constant value of type User:
final User user = reader.get<User>(constantReaderOfUser);
copied to clipboard
A short program demonstrating how to retrieve a constant of type User
is located at examples/bin/user_example.dart.
Limitations #


Constants retrievable with GenericReader must have
a built-in Dart type, a type made available by depending on a package, or a type defined in the file being read.
The functions matching the static type of an analyzer element with the type
of a runtime object do not work with relative imports.
E.g. the demos in folder example/bin read types that are provided
by the package test_types located in the subfolder with the same name.


Defining decoder functions for each data-type has its obvious limitiations when it comes to generic types. In practice, however, generic classes are often designed in such a manner that only few type parameters are valid or likely to be useful. Constants that need to be retrieved during the source-generation process are most likely annotations and simple data-types that convey information to source code generators. A demonstration on how to retrieve constant values with generic type is presented in example.


Examples #
For further information on how to use GenericReader to retrieve constants of
arbitrary type see example.
Features and bugs #
Please file feature requests and bugs at the issue tracker.

License:

For personal and professional use. You cannot resell or redistribute these repositories in their original state.

Files In This Product:

Customer Reviews

There are no reviews.