connect

lively.bindings – how to use connect

connect : 以声明方式定义源对象(source object)与目标对象(target object)之间的数据流连接。

1
2
3
4
5
6
7
// create source and target objects
var source = { sourceData: null };
var target = { targetData: null };
// connect source.sourceData -> target.targetData
connect(source, "sourceData", target, "targetData");
source.sourceData = 3;
target.targetData; // returns 3

Converter:

1
2
3
4
5
6
7
8
9
obj1 = { x: "foo" };
obj2 = { y: "123" };
connect(obj1, "x", obj2, "y", {
	converter: function (val) {
		return val % 7;
	},
});
obj1.x = 10;
obj2.y; //  3

Updater

1
2
3
4
5
6
7
8
obj = {};
connect(obj, "x", $world, "alert", {
	updater: function ($upd, val) {
		for (var i = 0; i < val; i++) $upd(i);
	},
});
obj.x = 3; // alerts 3 times
obj.x = 0; // no alert, we don't trigger anything

Disconnecting

1
disconnect(source, 'sourceData', target, 'targetData'); or disconnectAll(source)

新旧版本差异

新版本: 在场景(Scene)树里, 选中 morph 对象,之后创建 connection

快捷键(KeyBindings)

与 emacs 相似。

KeyBindings

自动补全

1
{keys: {win: "Ctrl-Space|Ctrl-Shift-P", mac: "Alt-Shift-Space|Alt-Space|Meta-Shift-P"}, command: "text completion"},

mac 下: option + space

lively.lang

lively.lang docs

提醒 : 内置对象(array、object)的特性与 Squeak 相似: Squeak 备忘

array

有许多 python-like 的便利操作。

以及 collection-like(与 Squeak 类似)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
var a = [1, 2, 3];
import { arr } from "lively.lang";
arr.max(a);

// create
arr.range(0, 5); // => [0,1,2,3,4,5]
arr.range(0, 10, 2); // => [0,2,4,6,8,10]
arr.withN(3, "Hello"); // => ["Hello","Hello","Hello"]
arr.genN(3, num.random); // => [46,77,95]

//invoke(array, method, arg1, arg2, arg3, arg4, arg5, arg6)
arr.invoke(["hello", "world"], "toUpperCase"); // => ["HELLO","WORLD"]

object

object docs

类似 squeak 里的 Dictionaries 对象

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import { obj } from "lively.lang";

// values
var obj1 = { x: 23, y: { z: 3 } };
obj.values(obj1); // => [22]

//inspect
obj.inspect(obj1);

// select

lively.classes

lively.classes: 支持实时开发的es6 class, 可动态修改,可序列化

lively.vm

eval-test

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import { expect } from "mocha-es6";
// import { runEval, syncEval, defaultTopLevelVarRecorderName } from "lively.vm/index.js";
import * as vm from "lively.vm";
vm.syncEval("1+1"); //使 option + i
/*
{
  isError: false,
  isEvalResult: true,
  isPromise: false,
  promiseStatus: "unknown",
  promisedValue: undefined,
  value: 2,
  warnings: []
}
*/

/*
Promise({status: "fulfilled", value: {
  isError: false,
  isEvalResult: true,
  isPromise: false,
  promiseStatus: "unknown",
  promisedValue: undefined,
  value: 2,
  warnings: []
}})
*/

vm.runEval("1+2")
	.then((result) => expect(result.value).equal(3))
	.catch((err) => expect(false, "got error in runEval " + err));

lively.ast

docs

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import * as ast from "lively.ast";
ast.stringify(ast.parse("1+2"));

ast.printAst(ast.parse("1+2"));

/*
:Program
\-.body[0]:ExpressionStatement
  \-.body[0].expression:BinaryExpression
    |-.body[0].expression.left:Literal
    \-.body[0].expression.right:Literal
*/

单独使用打包好的 lively.ast: lively.ast/examples

自定义模块

在 browser 中 创建/加载/修改 自定义模块

Hello World

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
export default class HelloWorld {
	constructor(a, b) {
		this.a = a;
		this.b = b;
	}

	log(x) {
		console.log(x);
	}
}

测试:

1
2
3
4
import HelloWorld from "HelloWorld/index.js";
let h = new HelloWorld("hello", "world");
h.a;
h.log("hi");

hello Morph

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import { Morph, morph, Icon, touchInputDevice } from "lively.morphic";

class HelloMorph extends Morph {
	constructor(props) {
		super(props);
		console.log("log");
	}
}

let a = new HelloMorph({});
a.openInWindow();
// 问题: 目前的默认morph,样式不如 Squeak

Adapter

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import EIMClient from "CodeLabAdapterClient/index.js";
let NODE_ID = "eim";
let HELP_URL = "https://adapter.codelab.club/";
let runtime = null;
let eim_client = new EIMClient(NODE_ID, HELP_URL, runtime);
//eim_client.adapter_base_client.emit_with_messageid('eim/extension_python', '1+1')

// promise
eim_client.adapter_base_client
	.emit_with_messageid("eim/extension_python", "1+1")
	.then((r) => {
		console.log(r);
	});

// async, return promise
async function emit_with_messageid(node_id, content){
	// todo resolve / reject -> timeout
 	let reply = await eim_client.adapter_base_client
	.emit_with_messageid(node_id, content);
	console.debug(`${reply}`);
 	return reply
}

emit_with_messageid("eim/extension_python", "1+1").then((data)=>{console.log(data)})

Linda

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import AdapterBaseClient from "CodeLabAdapterClient/codelab_adapter_base_lively.js";
let NODE_ID = "linda/js/client";
let HELP_URL = "https://adapter.codelab.club/user_guide/Linda/";
let runtime = null;
let adapter_client = new AdapterBaseClient(NODE_ID, HELP_URL, runtime);

await adapter_client.linda_out([1,2,3]).then((data)=>{console.log("linda",data); return data}) 

tuple = await adapter_client.linda_in(["hi", "lively", "*"]).then((data)=>{console.log("linda",data); return data})

tuple = await adapter_client.linda_in(["hi", "python", "from Lively"]).then((data)=>{console.log("linda",data); return data})

tuple = await adapter_client.linda_in(["hello", "lively", "*"]).then((data)=>{console.log("linda",data); return data})

await adapter_client.linda_in([1,2,5], 1000).then((data)=>{console.log("linda",data); return data}) //超时

参考