Skip to content

Instantly share code, notes, and snippets.

@nyteshade
Last active December 10, 2023 08:02
Show Gist options
  • Save nyteshade/d67304151b4f15ff5908652e1a9476c0 to your computer and use it in GitHub Desktop.
Save nyteshade/d67304151b4f15ff5908652e1a9476c0 to your computer and use it in GitHub Desktop.
Tickers are small state objects that are designed to increment or decrement values within themselves
import { Ticker } from './ticker.js'
/**
* The `Count` class extends the `Ticker` class and provides additional methods
* for arithmetic operations on the count value, like adding, subtracting,
* multiplying, and dividing by a specified delta value.
*/
class Count extends Ticker {
/**
* Adds a specified delta value to the current count value and returns the
* updated `Count` instance.
*
* @param {number} delta - The amount to add to the current count value.
* @returns {Count} The `Count` instance, updated with the new count value.
*/
add(delta) {
this.value += delta
return this
}
/**
* Subtracts a specified delta value from the current count value and returns
* the updated `Count` instance.
*
* @param {number} delta - The amount to subtract from the current count value.
* @returns {Count} The `Count` instance, updated with the new count value.
*/
sub(delta) {
this.value -= delta
return this
}
/**
* Multiplies the current count value by a specified delta value and returns the
* updated `Count` instance.
*
* @param {number} delta - The factor to multiply the current count value by.
* @returns {Count} The `Count` instance, updated with the new count value.
*/
multiply(delta) {
this.value *= delta
return this
}
/**
* Divides the current count value by a specified delta value and returns the
* updated `Count` instance.
*
* @param {number} delta - The divisor to divide the current count value by.
* @returns {Count} The `Count` instance, updated with the new count value.
*/
divide(delta) {
this.value /= delta
return this
}
}
import { Ticker } from './ticker.js'
/**
* LiminalTicker extends the Ticker class, providing enhanced functionality with
* threshold monitoring and callback execution. It is designed to trigger a callback
* when its value reaches or surpasses a specified threshold. The class allows for
* customizable threshold comparison logic and callback functions, making it flexible
* for various use cases.
*/
class LiminalTicker extends Ticker {
/**
* Constructs a LiminalTicker object with initial value, threshold, and callback
* functions.
*
* @param {any} initialValue - The initial value of the ticker. While it defaults
* to 0, it can be set to any type, depending on the intended use of the ticker.
* @param {any} threshold - The threshold value to trigger the callback. The type
* should be compatible with the type of initialValue for proper comparison.
* @param {Function} thresholdCallback - A function to be called when the ticker
* value meets or exceeds the threshold. It defaults to a no-operation function
* if not provided.
* @param {Function} thresholdMet - A predicate function that determines if the
* threshold condition is met. It receives the current value and the threshold
* as arguments and returns a boolean. By default, it checks if value is greater
* than or equal to the threshold, suitable for numeric comparisons.
*/
constructor(
initialValue = 0,
threshold = 0,
thresholdCallback = function() {},
thresholdMet = (value, threshold) => value >= threshold
) {
super(initialValue);
this.threshold = threshold;
// Bind the callbacks if they're functions
this.thresholdCallback = typeof thresholdCallback === 'function'
? thresholdCallback.bind(this)
: function() {};
this.thresholdMet = typeof thresholdMet === 'function'
? thresholdMet.bind(this)
: (value, threshold) => value >= threshold;
// Override the value property
Object.defineProperty(this, 'value', {
get: () => this._value,
set: (newValue) => {
this._value = newValue;
this.checkThreshold();
},
configurable: true,
enumerable: true
});
this.value = initialValue;
}
/**
* Checks whether the current ticker value meets or exceeds the threshold. If the
* condition is met and the threshold callback has not been previously triggered, the
* callback function is executed. The callback will not be triggered again until the
* value falls below the threshold and then meets or exceeds it again.
*/
checkThreshold() {
if (this.thresholdMet(this.value, this.threshold)) {
this.thresholdCallback(this.value, this.threshold);
}
}
}
import { Ticker } from './ticker.js'
/**
* The `Strings` class extends the `Ticker` class to manipulate an array of strings.
* It provides methods for adding, removing, and joining strings with a separator.
*/
export class Strings extends Ticker {
/**
* Constructs a `Strings` object with an initial array of strings.
*
* @param {...string} strings - An array of strings to initialize the `Strings` object.
*/
constructor(...strings) {
super(
[...strings],
function increment(string) { this.value.push(string) },
function decrement(string) {
if (this.value.includes(string))
this.value.splice(this.value.indexOf(string), 1)
else
this.value.pop()
},
function reset() { this.value = this.initialValue },
function primitive() { return this.value.join(this.separator ?? '') }
)
this.separator = ''
}
/**
* Sets a separator string for joining the internal array of strings.
*
* @param {string} separator - The separator string to use for joining.
* @returns {Strings} The `Strings` instance, to allow method chaining.
*/
setSeparator(separator) {
this.separator = separator
return this
}
/**
* Adds one or more strings to the end of the internal array.
*
* @param {...string} args - The strings to add to the array.
* @returns {Strings} The `Strings` instance, to allow method chaining.
*/
push(...args) {
this.value.push(...args)
return this
}
/**
* Retrieves the last string in the internal array.
*
* @type {string} - The last string in the array.
*/
get last() {
return this.value[this.value.length - 1]
}
/**
* Retrieves the first string in the internal array.
*
* @type {string} - The first string in the array.
*/
get first() {
return this.value[0]
}
/**
* Overrides the `Symbol.toStringTag` to return the class name when converted to
* a string. Useful for debugging and logging.
*
* @type {string} - The class name.
*/
get [Symbol.toStringTag]() {
return this.constructor.name
}
}
/**
* The Ticker class is a customizable counter that can be incremented, decremented,
* reset, and converted to a primitive value.
*/
class Ticker {
/**
* Creates a quick ticker object that can be used to keep track of counts. Think of it
* like a stopwatch that can be started, stopped, and reset. If the value is not a
* number, you can also supply custom functions that handle the incrementing,
* decrementing, and resetting of the value. If a primitive constructor is supplied,
* the value will be converted to that type when it is converted to a primitive value.
*
* Notable for customizations is that if non big-arrow functions are supplied to
* incrementer, decrementer, or resetter, they will be bound to the ticker object
* instance before being invoked. Additionally any parameters passed to the functions
* tick, increment, decrement, or reset will be passed to the customized functions
* when executed.
*
* @param [value=0] - The initial value of the object. It defaults to 0 if no
* value is provided.
* @param [incrementer] - The incrementer parameter is a function that increases
* the value of the "value" property by 1.
* @param [decrementer] - The `decrementer` parameter is a function that
* decreases the value of the `value` property by 1.
* @param [resetter] - The `resetter` parameter is a function that sets the
* `value` property of the object to 0.
* @param [primitive] - The "primitive" parameter is a reference to the Number
* constructor function. It is used to specify the type of the "value" property.
* By default, it is set to the Number constructor function, but you can pass any
* other constructor function for a different type, such as String or Boolean.
*/
constructor(
value = 0,
incrementer = function increment() { this.value += 1 },
decrementer = function decrement() { this.value -= 1 },
resetter = function reset() { this.value = this.initialValue },
primitive = undefined
) {
Object.assign(this, {
value,
initialValue: value,
incrementer,
decrementer,
resetter,
primitive
})
if (!this.primitive) {
this.primitive = Ticker.detectPrimitive(value)
}
}
static detectPrimitive(fromValue) {
if (typeof fromValue === 'number') {
this.primitive = Number
} else if (typeof fromValue === 'string') {
this.primitive = String
}
}
/**
* The tick function calls the incrementer function and returns the current
* object.
*
* @param args - The "args" parameter is a rest parameter that allows the
* function to accept any number of arguments as an array.
* @returns The `tick` method is returning the current instance of the object
* (`this`).
*/
tick(...args) {
this.incrementer.bind(this)(...args);
return this;
}
/**
* The increment function takes in any number of arguments, binds the incrementer
* function to the current object, and then returns the object itself.
*
* @param args - The "args" parameter is a rest parameter that allows the
* function to accept any number of arguments as an array.
* @returns the object on which it is called.
*/
increment(...args) {
this.incrementer.bind(this)(...args);
return this;
}
/**
* The "decrement" function binds the "decrementer" function to the current
* object and then returns the object itself.
*
* @param args - args is a rest parameter that allows the function to accept any
* number of arguments as an array.
* @returns The "this" object is being returned.
*/
decrement(...args) {
this.decrementer.bind(this)(...args);
return this;
}
/**
* The "reset" function is a method that resets the state of an object and
* returns the object itself.
*
* @param args - The "args" parameter is a rest parameter that allows the
* function to accept any number of arguments as an array.
* @returns The `reset` method is returning the instance of the object on which
* it is called.
*/
reset(...args) {
this.resetter.bind(this)(...args);
return this;
}
/**
* The above function returns the name of the constructor of an object.
*
* @returns The name of the constructor function.
*/
get [Symbol.toStringTag]() {
return this.constructor.name
}
/**
* The above function defines a method that converts an object to a primitive
* value.
*
* @param hint - The `hint` parameter is a string that indicates the preferred
* type of the conversion. It can have one of the following values:
* @returns The `primitive` value of `this.value`.
*/
[Symbol.toPrimitive](hint) {
return (this.primitive ?? Number)(this.value)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment