dart_epoxy 0.1.0

  • README.md
  • Installing
  • Versions
  • 0

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]
0
Overall:
Weighted score of the above. [more]
0
Learn more about scoring.

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

  • Dart: 2.0.0
  • pana: 0.11.8

Platforms

Detected platforms: web, other

Primary library: package:dart_epoxy/dart_epoxy.dart with components: mirrors.

Issues and suggestions

Fix lib/src/bindable.dart.

Analysis of lib/src/bindable.dart failed with 6 errors, 2 hints, including:

line 103 col 42: The element type 'BaseBindable<T>' can't be assigned to the list type 'Bindable'.

line 106 col 42: The element type 'BaseBindable<T>' can't be assigned to the list type 'Bindable'.

line 123 col 35: The return type 'BaseWrappedValue<bool>' isn't a 'bool', as defined by the method '=='.

line 133 col 53: Default values of an optional parameter must be constant.

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

Fix lib/src/reindexed_bindable_list.dart.

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>'.

Maintain CHANGELOG.md.

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

Add SDK constraint in pubspec.yaml.

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

Fix additional 10 files with analysis or formatting issues.

Additional issues in the following files:

  • lib/src/bindable_collection.dart (6 errors)
  • lib/src/async_bindables.dart (11 errors)
  • lib/src/const.dart (12 errors, 1 hint)
  • lib/src/mapped_bindable_list.dart (5 errors)
  • lib/src/bindable_list.dart (2 errors)
  • lib/src/epoxy_controller.dart (2 errors, 1 hint)
  • 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.)

The description is too short.

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

Package is pre-v1 release.

While there is nothing inherently wrong with versions of 0.*.*, it usually means that the author is still experimenting with the general direction of the API.

Maintain an example.

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