pip-services3-commons-nodex
Version:
Portable abstractions and patterns for Pip.Services in Node.js / ES2017
118 lines (106 loc) • 3.62 kB
text/typescript
/** @module reflect */
/**
* Helper class to perform method introspection and dynamic invocation.
*
* This class has symmetric implementation across all languages supported
* by Pip.Services toolkit and used to support dynamic data processing.
*
* Because all languages have different casing and case sensitivity rules,
* this MethodReflector treats all method names as case insensitive.
*
* ### Example ###
*
* let myObj = new MyObject();
*
* let methods = MethodReflector.getMethodNames();
* MethodReflector.hasMethod(myObj, "myMethod");
* MethodReflector.invokeMethod(myObj, "myMethod", 123);
*/
export class MethodReflector {
private static matchMethod(methodName: string, methodValue: any, expectedName: string): boolean {
if (typeof methodValue !== "function") return false;
if (methodName == "constructor") return false;
if (methodName.startsWith('_')) return false;
if (expectedName == null) return true;
return methodName.toLowerCase() == expectedName;
}
/**
* Checks if object has a method with specified name..
*
* @param obj an object to introspect.
* @param name a name of the method to check.
* @returns true if the object has the method and false if it doesn't.
*/
public static hasMethod(obj: any, name: string): boolean {
if (obj == null) {
throw new Error("Object cannot be null");
}
if (name == null) {
throw new Error("Method name cannot be null");
}
name = name.toLowerCase();
while (obj != null && Object.getPrototypeOf(obj) != null) {
let properties = Object.getOwnPropertyNames(obj)
for (let method of properties) {
let methodValue = obj[method];
if (MethodReflector.matchMethod(method, methodValue, name)) {
return true;
}
}
obj = Object.getPrototypeOf(obj)
}
return false;
}
/**
* Invokes an object method by its name with specified parameters.
*
* @param obj an object to invoke.
* @param name a name of the method to invoke.
* @param args a list of method arguments.
* @returns the result of the method invocation or null if method returns void.
*/
public static invokeMethod(obj: any, name: string, ...args: any[]): any {
if (obj == null) {
throw new Error("Object cannot be null");
}
if (name == null) {
throw new Error("Method name cannot be null");
}
name = name.toLowerCase();
while (obj != null && Object.getPrototypeOf(obj) != null) {
let properties = Object.getOwnPropertyNames(obj)
for (let method of properties) {
let methodValue = obj[method];
try {
if (MethodReflector.matchMethod(method, methodValue, name)) {
return methodValue.apply(obj, args);
}
} catch (ex) {
// Ignore exceptions
}
}
obj = Object.getPrototypeOf(obj)
}
return null;
}
/**
* Gets names of all methods implemented in specified object.
*
* @param obj an objec to introspect.
* @returns a list with method names.
*/
public static getMethodNames(obj: any): string[] {
let methods: string[] = [];
while (obj != null && Object.getPrototypeOf(obj) != null) {
let properties = Object.getOwnPropertyNames(obj)
for (let method of properties) {
let methodValue = obj[method];
if (MethodReflector.matchMethod(method, methodValue, null)) {
methods.push(method);
}
}
obj = Object.getPrototypeOf(obj)
}
return methods;
}
}