dart_epoxy 0.1.0

  • README.md
  • Installing
  • Versions
  • 5

Epoxy

The reactive glue for Dart

Epoxy is a small library that enables fully reactive programming in Dart using native syntax that blends in with the rest of the language. The goal of Epoxy is to help you build robust data models that are compact and intuitively understandable, which can then serve as the backbone of your entire app. With reactive programming, everything is built around the data itself, not events or callbacks or run loops.

What is reactive programming?

You can think of reactive programming like an Excel spreadsheet: Some cells contain raw data and others are calculated values that update automatically when any of their input cells change. For example, you can add in a list of all your monthly expenses and then set another cell to display the sum total of all of them, to help you budget. When you add, change, or remove an expense, the sum total automatically updates with it. Your spreadsheet, which is a simple data model of sorts, will always be internally consistent.

Put in programming terms: Reactive programming explicitly models not just raw values but also the relationships between them. This makes your code shorter and more declarative by eliminating glue code (e.g. ‘Add a new expense and then re-calculate the sum variable and then tell the UI to update’) and replacing it with a graph of dependencies (e.g. ‘The UI depends on the sum which depends on the expenses’). The graph can change dynamically such that each node has only the dependencies it actually needs at any given time, which means that not only will your reactive code be shorter and more robust, it will often also be faster!

Why Epoxy?

Reactive programming is probably familiar to most frontend engineers. Facebook’s React framework is an obvious example of it — as are most other JavaScript UI frameworks, from Knockout to Polymer. These frameworks are great, but they don't go far enough. Projects built with reactive frontends still interface with the backend through old-fashioned imperative glue code. This is the reason why things like Redux and Immutable.js were invented — to cut back on the tangled mess of buggy code that goes between the reactive UI layer and the imperative data model used by the rest of the app.

But, wait a minute, why do we have two different models in the first place? Why not write backend code that uses the same reactive data model as the frontend, and then just plug it in directly?

Epoxy is not a UI framework but rather a common standard on which many different frameworks can be built. An Epoxy-based database wrapper could output Epoxy objects that can be plugged directly into an Epoxy-based UI framework. Then, whenever the database updates, the view automatically updates with it, and vice versa! Epoxy is not a platform or a mindset or a specific way of building an app — it is simply the reactive glue (get it?) that binds all of the different components together. What those components are and how they work is up to you.

Some Code Examples

Create a computed variable by adding bindables:

final bindableA = new Bindable(4);
final bindableB = bindableA + 10;
expect(bindableB.value, equals(14));

bindableA.value = 10;
expect(bindableB.value, equals(20));

Keep a running total of items in a list:

final expenses = new BindableList([1, 2, 3, 4]);
final sum = expenses.reduce((val1, val2) => val1 + val2);
expect(sum.value, equals(10));

expenses.add(5);
expect(sum.value, equals(15));

expenses[0] = 0;
expect(sum.value, equals(14));

Maintain a dynamic selection from a list:

final letters = new BindableList(['A', 'B', 'C', 'D', 'E']);
final selectedIndex = new Bindable(0);
final selection = letters[selectedIndex];
expect(selection, bindableEquals('A'));

selectedIndex.value = 2;
expect(selection, bindableEquals('C'));

You can create your own custom bindable classes with more functionality:

class BindableLocation extends BindableObject {
    // This bindable will be published as this.latitude, with getters and setters to track
    // changes. The $ prefix is a convention, not a rule. The only hard rule is that the
    // name of the bindable property must be different from its published name ('latitude').
    final $latitude = new PropertyBindable('latitude', 100);
    final $longitude = new PropertyBindable('longitude', 50);
}

final bindableLocation = new BindableLocation();
expect(bindableLocation.latitude, equals(100));
expect(bindableLocation.longitude, equals(50));

Generate a reactive version of the fibonacci sequence:

final fibonacci = new BindableList([1, 1]);
for (var i = 0; i < 10; i++) fibonacci.add(fibonacci[i] + fibonacci[i + 1]);
expect(fibonacci.value, equals([1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144]));

// Batching changes means that each computed value in the list will only need to update once.
Epoxy.batchChanges(() {
    fibonacci[0] = 2;
    fibonacci[1] = 2;
});
expect(fibonacci.value, equals([2, 2, 4, 6, 10, 16, 26, 42, 68, 110, 178, 288]));

Automatically make everything awesome:

final stuffList = new BindableList(['Dart', 'Epoxy']);
final awesomeList = stuffList.map((item) => item + ' is awesome!');
expect(awesomeList[0].value, equals('Dart is awesome!'));

stuffList.add('Reactive Programming')
expect(awesomeList[2].value, equals('Reactive Programming is awesome!'));

Testing

Unit tests can be run with pub run test

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  dart_epoxy: ^0.1.0

2. Install it

You can install packages from the command line:

with pub:


$ pub get

Alternatively, your editor might support pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:dart_epoxy/dart_epoxy.dart';
  
Version Uploaded Documentation Archive
0.1.0 Nov 25, 2017 Go to the documentation of dart_epoxy 0.1.0 Download dart_epoxy 0.1.0 archive
Popularity:
Describes how popular the package is relative to other packages. [more]
0
Health:
Code health derived from static analysis. [more]
0
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
25
Overall:
Weighted score of the above. [more]
5
Learn more about scoring.

We analyzed this package on Oct 10, 2018, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.0.0
  • pana: 0.12.4

Platforms

Detected platforms: unsure

Low code quality prevents platform classification.

Health issues and suggestions

Fix lib/src/const.dart. (-96.85 points)

Analysis of lib/src/const.dart failed with 12 errors, 1 hint, including:

line 32 col 83: The operator '+' isn't defined for the class 'Object'.

line 33 col 83: The operator '-' isn't defined for the class 'Object'.

line 34 col 83: The operator '*' isn't defined for the class 'Object'.

line 35 col 83: The operator '/' isn't defined for the class 'Object'.

line 36 col 83: The operator '^' isn't defined for the class 'Object'.

Fix lib/src/reindexed_bindable_list.dart. (-95.84 points)

Analysis of lib/src/reindexed_bindable_list.dart failed with 11 errors, 3 hints, including:

line 57 col 31: The argument type 'List<O>' can't be assigned to the parameter type 'List<T>'.

line 68 col 14: The setter '_currentIndices' isn't defined for the class 'ReindexedBindableList<T, O>'.

line 68 col 32: The method 'reindexFunction' isn't defined for the class 'ReindexedBindableList'.

line 70 col 18: The method '_updateIndices' isn't defined for the class 'ReindexedBindableList<T, O>'.

line 76 col 51: The getter '_reindexedChangeStream' isn't defined for the class 'ReindexedBindableList<T, O>'.

Fix lib/src/async_bindables.dart. (-95.78 points)

Analysis of lib/src/async_bindables.dart failed with 11 errors, including:

line 8 col 12: The name 'T' isn't a type so it can't be used as a type argument.

line 29 col 5: Undefined name 'protected' used as an annotation.

line 32 col 37: The return type 'V' isn't a 'void', as defined by the method 'recompute'.

line 34 col 18: The name 'T' isn't a type so it can't be used as a type argument.

line 37 col 16: The name 'T' isn't a type so it can't be used as a type argument.

Fix additional 9 files with analysis or formatting issues. (-331.62 points)

Additional issues in the following files:

  • lib/src/bindable.dart (6 errors, 2 hints)
  • lib/src/bindable_collection.dart (6 errors)
  • lib/src/mapped_bindable_list.dart (5 errors)
  • lib/src/epoxy_controller.dart (2 errors, 1 hint)
  • lib/src/bindable_list.dart (2 errors)
  • lib/src/bindable_object.dart (4 hints)
  • lib/src/bindable_map.dart (2 hints)
  • lib/src/change_record.dart (Run dartfmt to format lib/src/change_record.dart.)
  • lib/src/property_bindables.dart (Run dartfmt to format lib/src/property_bindables.dart.)

Maintenance issues and suggestions

Fix platform conflicts. (-20 points)

Low code quality prevents platform classification.

Maintain CHANGELOG.md. (-20 points)

Changelog entries help clients to follow the progress in your code.

Add SDK constraint in pubspec.yaml. (-5 points)

For information about setting SDK constraint, please see https://www.dartlang.org/tools/pub/pubspec#sdk-constraints.

The description is too short. (-20 points)

Add more detail about the package, what it does and what is its target use case. Try to write at least 60 characters.

Maintain an example. (-10 points)

Create a short demo in the example/ directory to show how to use this package. Common file name patterns include: main.dart, example.dart or you could also use dart_epoxy.dart.

Dependencies

Package Constraint Resolved Available
Direct dependencies
meta >=1.1.2 <2.0.0 1.1.6
Dev dependencies
matcher any
test any