bindings 0.9.3

Smart & Sweet data-binding impl. on Signals.

Released 2016-07-04.

To install, run:

haxelib install bindings 0.9.3

See using Haxelib in Haxelib documentation for more information.

Maintainerfzzr
Websitehttps://bitbucket.org/fzzr/hx.bindings
Current version0.9.3
StatisticsInstalled 75 times
LicenseMIT
Tags bind, binding, cross

README.md

Smart & Sweet cross-platform data-binding impl. on Signals.

Build status

  • highly macro-powered
  • with minimal overhead

Compatibility

Compatible with targets:

  • Flash
  • Java
  • Neko
  • C++
  • PHP
  • JS
  • Python
  • Lua

C# in future plans.

Install:

Stable release: haxelib install bindings.

Development version:

haxelib hg bindings https://bitbucket.org/fzzr/hx.bindings

Then add to your hxml: -lib bindings.

Usage:

  1. implements hx.binding.IBindable;
  2. Mark fields with @:bindable meta;
  3. Now this fields can give you onChange-signal via: field! Haxe 3.3 syntax (postfix !); field.signal() standard syntax;
  4. Use mixin using hx.binding.Tool for fast binding a to b;
  5. Bind it to any expression a!.bind(b), where b is any possible expression;

haxe using hx.binding.Tool;

class Example implements hx.binding.IBindable {

@:bindable public static var one:String = "one";
@:bindable var two:String = "two";
@:bindable var three(default, null):String = "three";

public function new()
{
	// one => two
	one!.bind(two);
	// two => three
	two!.bind(three);
	// three => one (Yeeeh, cycle!)
	three!.bind(one);

	// set new value:
	one = "new value";

	trace(one); // "new value"
	trace(two); // "new value"
	trace(three); // "new value"

	// --- //

	// add watcher / listener:
	function watcher(value)
		trace('watcher: new value: $value');
	two!.add(watcher);

	// set new value:
	one = "42"; // "watcher: new value: 42"
	two = "WOW!"; // "watcher: new value: WOW!"
}

}

Defines:

  • binding-strict If false/0 or not defined then more validation for bindings and inner assignments;
  • binding-limit Maximum limit for total num of bindable fields, e.g.: -D binding-limit=100. Please don't use!
  • binding-debug Prints all bindable fields and all bindings; -D binding-debug=warn Make warnings for all bindable fields and all bindings instead print it; -D binding-debug=line Print bindings sorted by line of expression; * -D binding-debug (default) Print bindings sorted by adding order (depending on the compiler).

Example binding-debug output:

log Bindings initiated in module ./test/MixinToolTest.hx: 1 / 10 : (line: 25) Foo.fieldA! -> data.fieldA 2 / 10 : (line: 26) data.fieldB! -> Foo.fieldB 3 / 10 : (line: 61) Foo.fieldA! -> localA 4 / 10 : (line: 109) Foo.fieldA.signal() -> data.fieldA 5 / 10 : (line: 110) data.fieldB.signal() -> Foo.fieldB

Bindings initiated in module ./test/BindingTest.hx: 6 / 10 : (line: 164) impl.myPrivateLocalField! -> impl.myPublicLocalField 7 / 10 : (line: 165) impl.myPublicLocalField! -> impl.myPrivateLocalField 8 / 10 : (line: 212) myStaticField -> myLocalNoneBindableField 9 / 10 : (line: 226) myLocalField <-> myStaticField 10 / 10 : (line: 277) myLocalField! <-> impl.myPrivateLocalField

Example binding-debug=warn output:

screenshot binding-debug=warn


How it works?

You create a variable anywhere. For example you have a class: haxe class Data implements IBindable {

@:bindable public var myBindableField:String;
public function new(){}

}

Next you have an instance of it and want to bind field:

haxe using hx.binding.Tool;

class Anywhere {

var enotherField:String;

public function foo()
{
	var d = new Data();
	// bind it:
	d.myBindableField!.bind(enotherField);

	// and now any value assigned to myBindableField will assign to enotherField too.
}

}

There is two key moments:

  • myBindableField! will transformed to "get my associated signal by ID" -> hx.binding.BindableFields.get(42), where ID is inlined integer (in this example it 42)
  • Look, method bind is a macro function from mixin hx.binding.Tool. It will return simple expression where in same context we adding listener to the associated signal. In the output the expression d.myBindableField!.bind(enotherField); will look like to next code: haxe hx.binding.BindableFields.get(42).add( function(value:String) {

    enotherField = value;
    

    });

  • Because class Data implements IBindable all fields with meta @:bindable will transformed: type will wrapped to abstract type with generated inlinable id of field; for field will created inlinable setter: haxe function set_myBindableField(value:String) if(value != myBindableField) {

    myBindableField = value;
    myBindableField!.dispatch(value); // will transformed to next line:
    // hx.binding.BindableFields.get(42).dispatch(value); // why - see the first moment.
    

    }

That is all.


Strict typing bonus - cool completion by compiler:

ScreenShot about completion

ScreenShot about completion

ScreenShot about completion