项目作者: perry-mitchell

项目描述 :
Hot method patching framework for handling environmental method differences
高级语言: JavaScript
项目地址: git://github.com/perry-mitchell/hot-patcher.git
创建时间: 2018-07-21T14:09:00Z
项目社区:https://github.com/perry-mitchell/hot-patcher

开源协议:MIT License

下载


Hot-Patcher

Hot method patching framework for handling environmental method differences

Build status npm version

About

Hot-Patcher provides a simple API to manage patched methods. I found while writing Buttercup that managing overwritten methods between environments (Node/Browser/React-Native) was becoming cumbersome, and having a single agreed-upon method of doing so was the best way to go.

Installation

Install Hot-Patcher from npm:

  1. npm install hot-patcher --save

NB: This is an ESM library.

Usage

Hot-Patcher is a class and can simply be instantiated:

  1. import { HotPatcher } from "hot-patcher";
  2. const hp = new HotPatcher();

Hot-Patcher is designed to be used with patchable tools:

  1. import { HotPatcher } from "hot-patcher";
  2. export class MyHelper {
  3. public patcher: HotPatcher;
  4. constructor() {
  5. this.patcher = new HotPatcher();
  6. }
  7. increment(arg: number): number {
  8. return this.patcher.patchInline<number>("increment", someArg => {
  9. return someArg + 1;
  10. }, arg);
  11. }
  12. }

You can then patch methods when required:

  1. import { MyHelper } from "./MyHelper.js";
  2. export function getHelper() {
  3. const helper = new MyHelper();
  4. helper.patch("increment", (val: number) => val + 2);
  5. return helper;
  6. }

Patched methods can easily be fetched later:

  1. import { getSharedPatcher } from "./patching.js";
  2. const randomString = getSharedPatcher().get("randomString");
  3. randomString(5); // Generates a random string
  4. // Or, execute the method directly:
  5. getSharedPatcher().execute("randomString", 5) // Generates a random string

You can check if a method is patched by using isPatched: patcher.isPatched("some method").

Inline patching and execution

Ideally you could wrap function implementation with a patch call, executing it on demand:

  1. function add(a: number, b: number): number {
  2. return patcher.patchInline("add", (a, b) => a + b, a, b);
  3. }
  4. patcher.isPatched("add"); // false
  5. add(1, 2); // 3
  6. patcher.isPatched("add"); // true
  7. // calling add() multiple times will call the patched method without "re-patching" it
  8. // over and over again..

Plugins - Chaining/Sequencing functions

You can use Hot-Patcher to create sequences of functions:

  1. patcher.plugin("increment", x => x * 2, x => x * 2);
  2. patcher.execute("increment", 2); // 8

Which is basically syntactic sugar for a regular patch() call:

  1. patcher
  2. .patch("increment", x => x * 2, { chain: true })
  3. .patch("increment", x => x * 2, { chain: true });
  4. patcher.execute("increment", 2); // 8

Executing a regular patch() without chain: true will overwrite all chained methods with the new method.

Calling patch() with chain: true when a method already exists will simply add the new method after the existing:

  1. patcher
  2. .patch("increment", x => x * 2, { chain: false }) // or simply without `chain` specified
  3. .patch("increment", x => x * 2, { chain: true });
  4. patcher.execute("increment", 2); // still 8

Restoring methods

Methods can be restored to their originally patched function by calling the restore method:

  1. const methodA = () => {};
  2. const methodB = () => {};
  3. patcher
  4. // methodA is now the current (and original)
  5. .patch("someMethod", methodA)
  6. // methodB is now the current
  7. .patch("someMethod", methodB);
  8. // Restore "someMethod" to methodA (original)
  9. patcher.restore("someMethod");

Use Sparingly

The intention of Hot-Patcher is not to push every method into a patching instance, but to provide a common API for specific methods which require patching in some specific environments or in situations where users/consumers are expected to provide their own custom implementations.