Skip to content

Dart packages that automatically generate data classes for you.

Notifications You must be signed in to change notification settings

priezz/data_classes

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Data and Sealed Classes generators

Hey there!

If you're reading this and want data classes to become a language-level feature of Dart, consider giving this issue a thumbs up. 👍

In the meantime, this library generates immutable data classes for you based on simple mutable blueprint classes. Here's how to get started:

1. 📦 Add these packages to your dependencies:

dependencies:
  data_classes: ^3.0.0

dev_dependencies:
  build_runner: ^1.7.1
  data_classes_generator: ^3.0.0

2. 🧬 Write a blueprint class. Let the name start with Mutable and annotate it with @DataClass():

import 'package:data_classes/data_classes.dart';

part 'my_file.g.dart';

@DataClass()
class MutableFruit {
  String name;
  @nullable String color;
}

By default, attributes are considered non-nullable. If you want an attribute to be nullable, annotate it with @nullable.

3. 🏭 Run dart run build_runner build in the command line (or flutter run build_runner build, if you're using Flutter). The implementation based on your mutable class will automatically be generated.

copy & copyWith

By default, a copy method will be generated that takes a mutating function:

var freshApple = const Fruit(
  name: 'apple',
  color: 'green',
);
var banana = freshApple.copy((fruit) =>
  fruit
    ..name = 'banana'
    ..color = 'yellow'
);

Sometimes, you have classes that are guaranteed to only have non-nullable variables. For those, you can opt in to generate a copyWith method!

@DataClass(generateCopyWith = true)
class MutableFruit {
  String name;
  String color;
}

var oldApple = freshApple.copyWith(
  color: 'brown',
);

value getters

Sometimes, you have enum values as fields. In that case, you have the option to generate getters directly on the immutable class:

enum Color { red, yellow, green, brown }
enum Shape { round, curved }

@DataClass()
class MutableFruit {
  @GenerateValueGetters(generateNegations = true)
  Color color;

  @GenerateValueGetters(usePrefix = true)
  Shape theShape;
}

var banana = Fruit(color: Color.yellow, theShape: Shape.curved);

banana.isYellow; // true
banana.isNotGreen; // true
banana.isTheShapeRound; // false

full example

Here's an example with all the features (except nullability, so copyWith works). To showcase prefixed type imports, the Color enum from above has been moved to a file named colors.dart.

import 'package:data_classes/data_classes.dart';

import 'colors.dart' as colors;

part 'main.g.dart';

enum Shape { round, curved }

/// A fruit with a doc comment.
@DataClass(generateCopyWith: true)
class MutableFruit {
  String name;

  /// The color of this fruit.
  @GenerateValueGetters(generateNegations: true)
  colors.Color color;

  @GenerateValueGetters(usePrefix: true)
  Shape shape;

  List<String> likedBy;
}

And here's the generated code:

/// A fruit with a doc comment.
@immutable
class Fruit {
  final String name;

  /// The color of this fruit.
  final colors.Color color;

  final Shape shape;

  final List<String> likedBy;

  // Value getters.
  bool get isRed => this.color == colors.Color.red;
  bool get isNotRed => this.color != colors.Color.red;
  bool get isYellow => this.color == colors.Color.yellow;
  bool get isNotYellow => this.color != colors.Color.yellow;
  bool get isGreen => this.color == colors.Color.green;
  bool get isNotGreen => this.color != colors.Color.green;
  bool get isBrown => this.color == colors.Color.brown;
  bool get isNotBrown => this.color != colors.Color.brown;
  bool get isShapeRound => this.shape == Shape.round;
  bool get isShapeCurved => this.shape == Shape.curved;

  /// Default constructor that creates a new [Fruit] with the given
  /// attributes.
  const Fruit({
    @required this.name,
    @required this.color,
    @required this.shape,
    @required this.likedBy,
  })  : assert(name != null),
        assert(color != null),
        assert(shape != null),
        assert(likedBy != null);

  /// Creates a [Fruit] from a [MutableFruit].
  Fruit.fromMutable(MutableFruit mutable)
      : name = mutable.name,
        color = mutable.color,
        shape = mutable.shape,
        likedBy = mutable.likedBy;

  /// Turns this [Fruit] into a [MutableFruit].
  MutableFruit toMutable() {
    return MutableFruit()
      ..name = name
      ..color = color
      ..shape = shape
      ..likedBy = likedBy;
  }

  /// Checks if this [Fruit] is equal to the other one.
  bool operator ==(Object other) {
    return other is Fruit &&
        name == other.name &&
        color == other.color &&
        shape == other.shape &&
        likedBy == other.likedBy;
  }

  int get hashCode {
    return hashList([name, color, shape, likedBy]);
  }

  /// Copies this [Fruit] with some changed attributes.
  Fruit copy(void Function(MutableFruit mutable) changeAttributes) {
    assert(
        changeAttributes != null,
        "You called Fruit.copy, but didn't provide a function for changing "
        "the attributes.\n"
        "If you just want an unchanged copy: You don't need one, just use "
        "the original. The whole point of data classes is that they can't "
        "change anymore, so there's no harm in using the original class.");
    final mutable = this.toMutable();
    changeAttributes(mutable);
    return Fruit.fromMutable(mutable);
  }

  /// Copies this [Fruit] with some changed attributes.
  Fruit copyWith({
    String name,
    colors.Color color,
    Shape shape,
    List<String> likedBy,
  }) {
    return Fruit(
      name: name ?? this.name,
      color: color ?? this.color,
      shape: shape ?? this.shape,
      likedBy: likedBy ?? this.likedBy,
    );
  }

  /// Converts this [Fruit] into a [String].
  String toString() {
    return 'Fruit(\n'
        '  name: $name\n'
        '  color: $color\n'
        '  shape: $shape\n'
        '  likedBy: $likedBy\n'
        ')';
  }
}

About

Dart packages that automatically generate data classes for you.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages