Skip to content

Instantly share code, notes, and snippets.

@gavinking
Last active December 6, 2016 19:13
Show Gist options
  • Save gavinking/eb6eea7544d9e9f3acc3b03ebc6d2f1c to your computer and use it in GitHub Desktop.
Save gavinking/eb6eea7544d9e9f3acc3b03ebc6d2f1c to your computer and use it in GitHub Desktop.
Using Rank-2 polymorphic generic functions and JavaScript Proxy to create a typesafe proxy API for Ceylon objects
import ceylon.collection {
ArrayList
}
"Create a typesafe proxy for the given [[instance]], that
intercepts method calls and attribute evaluations."
Instance proxy<Instance>(Instance instance)(call, get) {
"Intercepts method invocations. Delegate to the method
of [[target]] by calling `method(args)`."
Return call<Return, Args>(Instance target, String name, Args args, Return method(Args args))
given Args satisfies Anything[];
"Intercepts attribute evaluation. The current attribute
value for [[target]] is [[attribute]]."
Type get<Type>(Instance target, String name, Type attribute);
dynamic {
dynamic handler = dynamic [
dynamic get(dynamic target, String name, dynamic _) {
dynamic field = target[name];
if ("$" in name || name=="constructor") {
return field;
}
if (field is Anything(*Nothing)) {
dynamic methodHandler = dynamic [
dynamic apply(dynamic target, dynamic self, dynamic args) {
value list = ArrayList<Anything>();
for (a in args) {
if (is Anything a) {
list.add(a);
}
}
return call<Anything, Anything[]> {
target = instance;
name = name;
args = list.sequence();
method() => target.apply(self, args);
};
}
];
return Proxy(field, methodHandler);
}
else {
return get<Anything> {
target = instance;
name = name;
attribute = field;
};
}
}
];
return Proxy(instance, handler);
}
}
class Person(shared String name,
shared void hello(String name, Integer count)
=> print("Hola ``name``! ".repeat(count))) {}
shared void run() {
value person = Person("Gavin");
Person p = proxy(person)
((_, name, args, method) {
print("calling '``name``()' with args ``args``");
return method(args);
},
(_, name, attribute) {
print("got '``name``'");
return attribute;
});
print(p.name);
p.hello("world", 3);
print(p is Person);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment