Monkey patching JavaScript to make it more Ruby!
npm install rubymonkeyUnashamedly monkey patching JavaScript to be more like Ruby.
Ruby (and Rails) has loads of really nice methods, now you can use them in JS as well!
Ruby Monkey helps to make your JavaScript code more code elegant, fun and productive!
Now you can write JS code like this:
``javascript`
[1,2,3].last // 3
[1,2,3].count // 3
(21).ordinalize // "21st"
"RubyMonkey".downcase.reverse // "yeknomybur"
[1,2,3].sum.squared // 36
["A","A","C","A","B","A","B"].tally // {"A": 4, "C": 1, "B": 2}
(1).day.ago // yesterday
`bash`
npm install rubymonkey
Then just add either require "rubymonkey" or import "rubymonkey" to the top of any JS file and suddenly coding in JS becomes a lot more fun and productive!
In general, if you know the Ruby methods you should be able to use them in almost the same way, with a few slight changes:
* Blocks change to arrow functions
* JavaScript does not support appending symbols to the end of function names, so Boolean methods can't end in a ?, so these have 2 versions, one without the ? at the end and another with is prepended to the beginning.
So for example, this Ruby:
`ruby`
[1,2,3].count{ |n| n.odd? }
Would be written in Ruby Monkey as either of the following:
`javascript`
[1,2,3].count( n => n.isOdd )
`javascript`
[1,2,3].count( n => n.odd )
Ruby has this really nice syntax to make calling methods on objects easier, so instead of [1,2,3].map { |n| n.next } you can just write [1,2,3].map(&:next)
JavaScript doesn't let you use & and doesn't have symbol literals, but you can use $ and it does have template literals and tag functions, so in Ruby Doo, you can do the same thing like this:
`javascriptnext
[1,2,3].map($)`
& number.isEvenChecks if the number is even.
`javascript`
(4).even; // true
(5).even; // false
& number.isOddChecks if the number is odd.
`javascript`
(3).odd; // true
(10).odd; // false
Converts the number to a string.
`javascript`
(42).to_s; // "42"
Returns the next integer.
`javascript`
(10).next; // 11
Rounds the number to the nearest integer.
`javascript`
(4.7).round; // 5
(4.2).round; // 4
Returns the smallest integer greater than or equal to the number.
`javascript`
(4.2).ceil; // 5
Returns the largest integer less than or equal to the number.
`javascript`
(4.9).floor; // 4
Returns an array of the digits of the number.
`javascript`
(123).digits; // [1, 2, 3]
Returns an array of all factors of the number.
`javascript`
(12).factors; // [1, 2, 3, 4, 6, 12]
Checks if the number is prime.
`javascript`
(7).prime; // true
(9).prime; // false
and number.isIntegerChecks if the number is an integer.
`javascript`
(10.5).integer; // false
(10).integer; // true
& number.isPositiveChecks if the number is positive.
`javascript`
(5).positive; // true
(-3).positive; // false
& number.isNegativeChecks if the number is negative.
`javascript`
(-10).negative; // true
(5).negative; // false
& number.isZeroChecks if the number is zero.
`javascript`
(0).zero; // true
(1).zero; // false
Returns the square of the number.
`javascript`
(4).squared; // 16
Returns the cube of the number.
`javascript`
(3).cubed; // 27
Returns the ordinal suffix of the number.
`javascript`
(1).ordinal; // "st"
(2).ordinal; // "nd"
(3).ordinal; // "rd"
(4).ordinal; // "th"
(11).ordinal; // "th"
Returns the number as an ordinal string.
`javascript`
(1).ordinalize; // "1st"
(2).ordinalize; // "2nd"
(3).ordinalize; // "3rd"
(4).ordinalize; // "4th"
(11).ordinalize; // "11th"
Iterates from the current number up to n, calling func if provided.
`javascript
(3).upto(6, console.log);
// Logs: 3, 4, 5, 6
(3).upto(6);
// Returns: [3, 4, 5, 6]
`
Executes func the given number of times, passing the index as an optional argument.
`javascript
(3).times(_ => console.log("Ruby!"));
// Logs: Ruby!Ruby!Ruby!
(3).times(i => console.log(Iteration: ${i}));`
// Logs: Iteration: 0, Iteration: 1, Iteration: 2
Returns the remainder of the number divided by n.
`javascript`
(10).mod(3); // 1
Returns an array containing the quotient and remainder of division by n.
`javascript`
(10).divmod(3); // [3, 1]
Computes the greatest common divisor (GCD) of the number and n.
`javascript`
(48).gcd(18); // 6
Computes the least common multiple (LCM) of the number and n.
`javascript`
(4).lcm(6); // 12
& number.isBetween(a,b)Checks if the number is between a and b (inclusive).
`javascript`
(5).between(1, 10); // true
(15).between(1, 10); // false
Checks if the number is strictly equal to n.
`javascript`
(5).eql(5); // true
(5).eql(3); // false
& number.divisble_by(n)Checks if the number is a multiple of n.
`javascript`
(10).multiple_of(5); // true
(10).multiple_of(3); // false
`javascript`
(10).divisible_by(5); // true
(10).divisible_by(3); // false
& number.factor_of(n)Checks if the number is a divisor (factor) of n.
`javascript`
(5).divisor_of(10); // true
(3).divisor_of(10); // false
`javascript`
(5).factor_of(10); // true
(3).factor_of(10); // false
Returns the predecessor (this - 1).
`javascript`
(10).pred; // 9
(1).pred; // 0
Iterates from the current number down to n, calling func if provided.
`javascript
(6).downto(3, console.log);
// Logs: 6, 5, 4, 3
(6).downto(3);
// Returns: [6, 5, 4, 3]
`
Returns the integer division result (floor of division).
`javascript`
(10).div(3); // 3
(7).div(2); // 3
Returns the modulo of the number divided by n. Alias for mod.
`javascript`
(10).modulo(3); // 1
(-10).modulo(3); // 2
Highest common factor. Alias for gcd.
`javascript`
(48).hcf(18); // 6
& number.isNonzeroisNonzero returns true if the number is not zero. nonzero returns the number itself if non-zero, otherwise undefined.
`javascript`
(5).isNonzero; // true
(0).isNonzero; // false
(5).nonzero; // 5
(0).nonzero; // undefined
Returns the absolute value of the number.
`javascript`
(-5).abs; // 5
(5).abs; // 5
Returns the sum of the number and n.
`javascript`
(5).add(3); // 8
& number.minus(n)Returns the difference of the number and n.
`javascript`
(10).subtract(3); // 7
(10).minus(3); // 7
Returns the product of the number and n.
`javascript`
(5).multiply(3); // 15
Returns the quotient of the number divided by n.
`javascript`
(10).divide(2); // 5
(7).divide(2); // 3.5
Returns the string reversed.
`javascript`
"hello".reverse; // "olleh"
`javascript`
"hello".size; // 5
`javascript`
"123".to_i; // 123
"abc".to_i; // 0
`javascript`
"12.34".to_f; // 12.34
"abc".to_f; // 0
`javascript`
"Hello".downcase; // "hello"
`javascript`
"hello".upcase; // "HELLO"
`javascript`
"hello world".upcase_first; // "Hello world"
Lowercases only the first character of the string.
"Hello World".downcase_first; // "hello World"
Removes leading, trailing, and multiple consecutive spaces.
`javascript`
" Hello world ".squish; // "Hello world"
Checks if the string is empty or contains only whitespace.
`javascript`
" ".blank; // true
"hello".blank; // false
Checks if the string is completely empty (not even whitespace).
`javascript`
"".empty; // true
" ".empty; // false
Removes _id from the end (if present) and replaces underscores with spaces, capitalizing the first letter.
`javascript`
"user_name".humanize; // "User name"
"post_id".humanize; // "Post"
Capitalizes each word in the string.
`javascript`
"hello world".titleize; // "Hello World"
Converts the string into a URL-friendly format (lowercase, hyphenated).
`javascript`
"Hello, World!".parameterize; // "hello-world"
`javascript`
"hello".chars; // ["h", "e", "l", "l", "o"]
Returns the number of times substring appears in the string.
`javascript`
"hello world".count("l"); // 3
`javascript`
"hello world".starts_with("hello"); // true
`javascript`
"hello world".ends_with("world"); // true
`javascript`
"hello".first; // "h"
`javascript`
"hello".first(2); // "he"
"hello".first(5); // "hello"
`javascript`
"hello".last; // "o"
`javascript`
"hello".last_(2); // "lo"
"hello".last_(5); // "hello"
Checks if the string is strictly equal to str.
`javascript`
("hello").eql("hello"); // true
("Hello!").eql("hello"); // false
Returns the string itself.
`javascript`
"hello".to_s; // "hello"
& string.blankisBlank and blank are aliases. Checks if the string is empty or contains only whitespace.
`javascript`
" ".isBlank; // true
"hello".blank; // false
& string.emptyisEmpty and empty are aliases. Checks if the string is completely empty (not even whitespace).
`javascript`
"".isEmpty; // true
" ".empty; // false
Returns the first element of the array.
`javascript`
[1, 2, 3].first; // 1
[].first; // undefined
Returns the second, third, fourth, or fifth element of the array.
`javascript`
[10, 20, 30].second; // 20
[10].third; // undefined
Returns the 42nd element (index 41) of the array.
`javascript`
Array(50).fill(0).map((_, i) => i + 1).forty_two; // 42
### array.third_to_last, array.second_to_last, array.last
Returns the third-to-last, second-to-last, or last element of the array.
`javascript`
[1, 2, 3, 4].second_to_last; // 3
[].last; // undefined
Returns true if the array is empty, false otherwise.
`javascript`
[].empty; // true
[1].empty; // false
Clears all elements from the array.
`javascript`
let arr = [1, 2, 3];
arr.clear;
console.log(arr); // []
Returns the length of the array.
`javascript`
[1, 2, 3].size; // 3
Returns the smallest or largest number in the array.
`javascript`
[5, 3, 9].min; // 3
[5, 3, 9].max; // 9
[].min; // undefined
Returns a new array with duplicate elements removed.
`javascript`
[1, 2, 2, 3].uniq; // [1, 2, 3]
Converts the array into a human-readable sentence.
`javascript`
["a", "b", "c"].to_sentence; // "a, b and c"
Returns a new array with null and undefined values removed.
`javascript`
[1, null, 2, undefined, 3].compact; // [1, 2, 3]
Converts the array into a string joined by /.
`javascript`
["users", 42, "edit"].to_param; // "users/42/edit"
Returns true if at least one element satisfies func, or if the array is not empty.
`javascript`
[1, 2, 3].any(x => x > 2); // true
[].any(); // false
Returns true if exactly one element satisfies func.
`javascript`
[1, 2, 3].one(x => x > 2); // true
[1, 2, 3, 4].one(x => x > 2); // false
Returns the sum of all elements, or applies func before summing.
`javascript`
[1, 2, 3].sum; // 6
Returns a new array without elements matching func.
[1, 2, 3, 4].reject(x => x % 2 === 0); // [1, 3]
Splits the array into two: one matching func, one not.
`javascript`
[1, 2, 3, 4].partition(x => x % 2 === 0); // [[2, 4], [1, 3]]
Returns the number of elements satisfying func, or the total length.
`javascript`
[1, 2, 3, 4].count(x => x % 2 === 0); // 2
[1, 2, 3].count(); // 3
Extracts values of the given property from an array of objects.
`javascript`
[{id: 1}, {id: 2}].pluck("id"); // [1, 2]
Returns a new array starting from index n.
`javascript
[10, 20, 30, 40].from(2); // [30, 40]
Returns all possible combinations of elements from both arrays.
`javascript`
[1, 2, 3].product([4,5]); // [[1,4], [1,5], [2,4],[2,5], [3,4], [3,5]]
Returns all possible combinations of n elements.
`javascript`
[1, 2, 3].combination(2); // [[1,2], [1,3], [2,3]]
Counts occurrences of each unique element.
`javascript`
["a", "b", "a"].tally(); // { a: 2, b: 1 }
Returns overlapping subarrays of size n.
`javascript`
[1, 2, 3, 4].each_cons(2); // [[1,2], [2,3], [3,4]]
Returns a rotated array by n places.
`javascript`
[1, 2, 3].rotate(); // [2, 3, 1]
Returns n random elements.
`javascript`
[1, 2, 3, 4].sample(2); // Random subset
Zips two arrays together.
`javascript`
[1, 2, 3].zip(["a", "b", "c"]); // [[1, "a"], [2, "b"], [3, "c"]]
Returns a merged array without duplicates.
`javascript`
[1, 2].union([2, 3], [3, 4]); // [1, 2, 3, 4]
Returns elements common to all arrays.
`javascript`
[1, 2, 3].intersection([2, 3, 4]); // [2, 3]
Returns a tuple of [min, max] values in the array.
`javascript`
[5, 1, 9, 3].minmax; // [1, 9]
Returns the product of all elements in the array.
`javascript`
[1, 2, 3, 4].multiply; // 24
Returns a shuffled copy of the array.
`javascript`
[1, 2, 3].shuffle; // e.g., [3, 1, 2]
Transposes a 2D array (swaps rows and columns).
`javascript`
[[1, 2], [3, 4]].transpose; // [[1, 3], [2, 4]]
Returns a sorted copy of the array (numeric sort).
`javascript`
[3, 1, 2].sort; // [1, 2, 3]
Flattens nested arrays by one level.
`javascript`
[[1, 2], [3, [4, 5]]].flatten; // [1, 2, 3, [4, 5]]
Alias for slice(n). Returns elements after dropping the first n.
`javascript`
[1, 2, 3, 4].drop(2); // [3, 4]
Sorts the array by the value returned from func. Pass 'desc' as the second argument to sort in descending order.
`javascript
// Sort strings by length
["apple", "fig", "banana"].sort_by(s => s.length);
// ["fig", "apple", "banana"]
// Sort strings by length descending
["apple", "fig", "banana"].sort_by(s => s.length, 'desc');
// ["banana", "apple", "fig"]
// Sort strings by last character
["apple", "banana", "cherry"].sort_by(s => s.last);
// ["banana", "apple", "cherry"]
// Sort objects by property
const users = [
{ name: "Charlie", age: 35 },
{ name: "Alice", age: 30 },
{ name: "Bob", age: 25 }
];
users.sort_by(u => u.age);
// [{ name: "Bob", age: 25 }, { name: "Alice", age: 30 }, { name: "Charlie", age: 35 }]
// Sort by computed value descending
const products = [
{ name: "Widget", price: 25, quantity: 10 },
{ name: "Gadget", price: 50, quantity: 3 },
{ name: "Gizmo", price: 15, quantity: 20 }
];
products.sort_by(p => p.price * p.quantity, 'desc');
// [Gizmo (300), Widget (250), Gadget (150)]
`
Safely retrieves a nested value using a sequence of keys or indexes.
Returns undefined if any step in the chain is missing.
`javascript`
[ { a: { b: 10 } } ].dig(0, "a", "b"); // 10
[ { a: {} } ].dig(0, "a", "c"); // undefined
Deep-compares two arrays for equality.
Uses an element’s custom .eql method if present, otherwise strict equality (===).
`javascript`
[1, 2, 3].eql([1, 2, 3]); // true
[1, 2, 3].eql([1, 2, "3"]); // false
Maps the array with func and removes null/undefined values (.compact).
`javascript`
[1, 2, 3].filter_map(n => (n % 2 === 0 ? n * 2 : null));
// [4]
Iterates over the array and yields each element with the provided object.
`javascript`
const acc = [];
[1, 2, 3].each_with_object(acc, (n, arr) => arr.push(n * 2));
acc; // [2, 4, 6]
Returns the first n elements of the array.
If n < 1, returns an empty array.
`javascript`
[1, 2, 3].first_(2); // [1,2]
[1, 2, 3].first_(3); // [1, 2, 3]
Returns the last n elements of the array.
If n < 1, returns an empty array.
`javascript`
[1, 2, 3].last_(2); // [2, 3]
[1, 2, 3].last_(3); // [1, 2, 3]
collect → map
all → every
select → filter
each → forEach
detect → find
inject → reduce
delete_if → reject
flat_map → flatMap
drop → slice
empty → isEmpty
Checks if an object has no keys.
`javascript`
({}).empty; // true
({ a: 1 }).empty; // false
Returns the number of keys in the object.
`javascript`
({ a: 1, b: 2 }).size; // 2
object.valuesReturns an array of the object's values.
``javascript`
({ a: 1, b: 2 }).values; // [1, 2]
Returns an array of the object's keys.
`javascript`
({ a: 1, b: 2 }).keys; // ["a", "b"]
Returns an array of [key, value] pairs.
`javascript`
({ a: 1, b: 2 }).entries; // [["a", 1], ["b", 2]]
Removes all properties from an object (mutates it).
const obj = { a: 1, b: 2 };
obj.clear
console.log(obj); // {}
Returns a new object with null and undefined values removed.
`javascript`
({ a: 1, b: null, c: undefined }).compact; // { a: 1 }
Returns a new object with key-value pairs where func(key, value) is true.
`javascript`
({ a: 1, b: 2 }).select(([k, v]) => v > 1); // { b: 2 }
Alias for select.
Returns a new object with key-value pairs where func(key, value) is false.
`javascript`
({ a: 1, b: 2 }).reject(([k, v]) => v > 1); // { a: 1 }
Alias for reject.
Checks if an object has a given key.
`javascript`
({ a: 1 }).has_key("a"); // true
({ a: 1 }).has_key("b"); // false
Checks if an object contains a given value.
`javascript`
({ a: 1, b: 2 }).has_value(2); // true
({ a: 1 }).has_value(3); // false
Returns the first key where the value matches, or undefined if not found.
`javascript`
({ a: 1, b: 2 }).key(2); // "b"
({ a: 1 }).key(3); // undefined
If func is provided, checks if any key-value pair matches func(key, value).
If func is omitted, returns true if the object is not empty.
`javascript`
({ a: 1, b: 2 }).any(); // true
({}).any(); // false
({ a: 1, b: 2 }).any(([k, v]) => v > 1); // true
Returns a new object excluding specified keys.
`javascript`
({ a: 1, b: 2, c: 3 }).except("b", "c"); // { a: 1 }
Returns a new object with keys transformed by func.
`javascript`
({ a: 1, b: 2 }).transform_keys(k => k.toUpperCase()); // { A: 1, B: 2 }
Returns a new object with values transformed by func.
`javascript`
({ a: 1, b: 2 }).transform_values(v => v * 10); // { a: 10, b: 20 }
Safely retrieves a nested value using a sequence of keys.
`javascript`
({ a: { b: { c: 42 } } }).dig("a", "b", "c"); // 42
({ a: {} }).dig("a", "x"); // undefined
Iterates over each [key, value] entry, calling func.
`javascript`
({ a: 1, b: 2 }).each(([k, v]) => console.log(k, v));
// Logs: "a" 1, "b" 2
Iterates over each key, calling func.
`javascript`
({ a: 1, b: 2 }).each_key(k => console.log(k));
// Logs: "a", "b"
Iterates over each value, calling func.
`javascript`
({ a: 1, b: 2 }).each_value(v => console.log(v));
// Logs: 1, 2
Returns the value for the given key.
`javascript`
({ a: 1, b: 2 }).fetch("a"); // 1
Returns an array of values for the given keys.
`javascript`
({ a: 1, b: 2, c: 3 }).fetch_values("a", "c"); // [1, 3]
Deep equality check between objects.
`javascript`
({ a: 1, b: 2 }).eql({ a: 1, b: 2 }); // true
({ a: 1 }).eql({ a: "1" }); // false
Returns a string representation of the object.
`javascript`
({ a: 1, b: 2 }).to_s; // "{ a: 1, b: 2 }"
each_pair → each
filter → select
includes → has_key
A lightweight set of extensions for working with dates, durations, and date ranges based on the Rails helper methods.
Includes:
* DateRange — iterate or inspect ranges of dates
* Duration — express time spans like (3).days or (2).months
* Prototype helpers on Date for navigation, ranges, and comparisons
* Convenience accessors like Date.today, Date.current, date.isToday
* Iterable ranges and unit-based iteration (each_day, each_month, etc.)
Returns true if the date falls inside the range (inclusive).
`javascript`
range.includes(Date.today); // true
Iterates day-by-day through the range, calling the callback for each date.
step controls the day increment.
`javascript`
range.each(d => console.log(d));
range.each(d => console.log(d), 2); // Every 2 days
Alias for .each.
Iterates through days in the range.
`javascript`
range.each_day(d => console.log(d));
Iterates through the range in weekly steps.
`javascript`
range.each_week(d => console.log(d)); // Every 7 days
range.each_week(d => console.log(d), 2); // Every 14 days
Iterates month-to-month, preserving the original day when possible
(and adjusting for month length differences automatically).
`javascript`
range.each_month(d => console.log(d));
Iterates in increments of 3 months.
`javascript`
range.each_quarter(d => console.log(d));
Iterates year-to-year through the range.
`javascript`
range.each_year(d => console.log(d));
Creates a duration object.
`javascript`
const d = new Duration({ days: 3, hours: 5 });
Shifts backward from Date.current.
`javascript`
(3).days.ago; // 3 days before now
Moves forward from the given date.
`javascript`
(2).weeks.since(Date.today);
Moves backward from the given date.
`javascript`
(1).month.before(Date.today);
Alias for duration.since.
`javascript`
(6).hours.after(Date.current);
Returns the date minus the duration.
`javascript`
(10).days.until(Date.today);
Shifts forward from Date.current.
`javascript`
(30).minutes.from_now;
Applies all duration components to the given date.
`javascript`
new Duration({ days: 1, months: 1 }).advance_from(Date.today);
All numbers gain convenience getters for generating a Duration:
`javascript`
second, seconds
minute, minutes
hour, hours
day, days
week, weeks
month, months
year, years
Example usage:
`javascript`
(3).days; // Duration { days: 3 }
(1).year; // Duration { years: 1 }
(2).weeks.from_now;
Returns a DateRange covering the full period.
`javascript`
Date.today.all_week.each(d => console.log(d));
Convenient accessors for the start or end of a period.
`javascript`
Date.today.at_beginning_of_month;
Date.today.at_end_of_year;
`javascript`
date.isYesterday, date.isToday, date.isTomorrow
Checks if the date falls within the corresponding day.
`javascript`
Date.today.isToday; // true
`javascript`
Date.current
Returns the current UTC date with full time precision.
`javascript`
Date.current;
Date.today
Returns today's UTC date at midnight.
`javascript`
Date.today;
Date.yesterday
Date.tomorrow
UTC midnight versions of today, yesterday and tomorrow.
Returns the previous day at the beginning of day.
`javascript`
Date.current.yesterday;
Returns the next day at the beginning of day.
`javascript`
Date.current.tomorrow;
Returns the number of days in the current month.
`javascript`
new Date(Date.UTC(2024, 1, 1)).days_in_month; // 29
Returns a new date advanced by the given duration.
`javascript`
Date.today.advance({ weeks: 1 });
Returns a new date with selected UTC fields replaced.
`javascript``
Date.current.change({ hour: 0, minute: 0 });