Functions
The Functions filter provides a large number of convenience methods Rubyists are familar with. Statements such as "252.3".to_i transform into parseInt("252.3"), or [1,3,5].yield_self { |arr| arr[1] } into (arr => arr[1])([1, 3, 5]). Generally you will want to include this filter in your configuration unless you have specific reason not to.
List of Transformations
.absMath.abs().all?.every(with block) or.every(Boolean)(without block).any?.some(with block) or.some(Boolean)(without block).ceilMath.ceil().charsArray.from().chrfromCharCode.clear.length = 0.compact.filter(x => x != null).compact!.splice(0, a.length, ...a.filter(x => x != null))(mutating)debuggerdebugger(JS debugger statement).define_methodklass.prototype.meth = function ....deletedelete target[arg].downcase.toLowerCase.each.forEach.each_keyfor (i in ...) {}.each_pairfor (let key in item) {let value = item[key]; ...}.each_value.forEach.each_with_index.forEach.end_with?.slice(-arg.length) == arg.empty?.length == 0.find_indexfindIndex.first[0].first(n).slice(0, n).flat_map {}.flatMap().floorMath.floor().freezeObject.freeze().group_by {}Object.groupBy()(ES2024+) or.reduce()fallback.group_by {|k,v| ...}destructuring support ([k, v]) => ....gsubreplace(//g).has_key?key in hash.include?.indexOf() != -1.indexindexOf(when using arg) orfindIndex(when using block).inspectJSON.stringify().join.join('')(Ruby defaults to"", JS to",").key?key in hash.keys()Object.keys().last[*.length-1].last(n).slice(*.length-1, *.length).lstrip.replace(/^\s+/, "").maxMath.max.apply(Math).max_by {}.reduce().member?key in hash.mergeObject.assign({}, ...).merge!Object.assign().method_defined?klass.prototype.hasOwnProperty(meth)ormeth in klass.prototype.minMath.min.apply(Math).min_by {}.reduce().negative?< 0.none?!.some(with block) or!.some(Boolean)(without block)[-n] = x[*.length-n] = xfor literal negative index assignment.new(size,default)== .new(size).fill(default).nil?== null.ordcharCodeAt(0).positive?> 0putsconsole.lograndMath.random.reject {}.filter(x => !(...))(negated condition).reject(&:method).filter(item => !item.method())(symbol-to-proc).replace.length = 0; ...push.apply(*).respond_to?right in left.rindex.lastIndexOf.roundMath.round().rstrip.replace(/s+$/, "").scan.match(//g).senddynamic method dispatch obj.send(:foo, x)becomesobj.foo(x)orobj[method](x).sort_by {}.toSorted()(ES2023+) or.slice().sort()fallback.sum.reduce((a, b) => a + b, 0).reduce(:+).reduce((a, b) => a + b)(symbol-to-proc for operators).reduce(:merge).reduce((a, b) => ({...a, ...b}))(hash merge).timesfor (let i = 0; i < n; i++).start_with?.startsWith(arg).upto(lim)for (let i=num; i<=lim; i+=1).downto(lim)for (let i=num; i>=lim; i-=1).step(lim, n).eachfor (let i=num; i<=lim; i+=n).step(lim, -n).eachfor (let i=num; i>=lim; i-=n)(0..a).to_a[...Array(a+1).keys()](b..a).to_aArray.from({length: (a-b+1)}, (_, idx) => idx+b)(b...a).to_aArray.from({length: (a-b)}, (_, idx) => idx+b).strip.trim.sub.replace.tap {|n| n}(n => {n; return n})(...).to_fparseFloat.to_iparseInt.to_s.toString.to_sym(removed - symbols are strings in JS) .to_jsonJSON.stringify(obj)typeof(x)typeof x(JS type checking operator).upcase.toUpperCase.yield_self {|n| n}(n => n)(...).zero?=== 0[-n][*.length-n]for literal values ofn[n...m].slice(n,m)[n..m].slice(n,m+1)[start, length].slice(start, start+length)(Ruby 2-arg slice)[n..m] = v.splice(n, m-n+1, ...v).slice!(n..m).splice(n, m-n+1)[/r/, n].match(/r/)[n][/r/, n]=.replace(/r/, ...)(1..2).each {|i| ...}for (let i=1; i<=2; i+=1)"string" * length"string".repeat(length)[element] * nArray(n).fill(element)[a, b] * nArray.from({length: n}, () => [a, b]).flat()array + [elements]array.concat([elements])@foo.call(args)this._foo(args)@@foo.call(args)this.constructor._foo(args)Array(x)Array.from(x)delete xdelete x(note lack of parenthesis)
Additional Features
.sub!and.gsub!become equivalentx = x.replacestatements.map!,.reverse!, and.select!become equivalent.splice(0, .length, *.method())statementssetIntervalandsetTimeoutallow block to be treated as the first parameter on the call- for the following methods, if the block consists entirely of a simple
expression (or ends with one), a
returnis added prior to the expression:sub,gsub,any?,all?,map,find,find_index. - New classes subclassed off of
Exceptionwill become subclassed off ofErrorinstead; and default constructors will be provided loop do...endwill be replaced withwhile (true) {...}n.times do...endandn.times { |i| ... }will be replaced withforloopsraise Exception.new(...)will be replaced withthrow new Error(...)block_given?will check for the presence of optional argument_implicitBlockYieldwhich is a function made accessible through the use ofyieldin a method body.alias_methodworks both inside of a class definition as well as called directly on a class name (e.g.MyClass.alias_method)define_methodandmethod_defined?work inside class bodies (with or without explicit receiver), including inside loops like[:a, :b].each { |m| define_method(m) { ... } }- Block parameter destructuring is supported:
.map {|k, v| ...}becomes.map(([k, v]) => ...)
Methods Always Called with Parentheses
Ruby allows calling methods without parentheses, but JavaScript requires them for
methods that return values. The following methods always output with () in JS,
even when written without parentheses in Ruby:
reverse, pop, shift, sort, dup, clone
arr.reverse.each { |x| puts x }
# => for (let x of arr.reverse()) { console.log(x) }
x = arr.pop
# => let x = arr.pop()
Methods Requiring Parentheses
Some Ruby method names like keys, values, index, max, etc. could also be
property accesses in JavaScript (e.g., on DOM nodes). To avoid incorrect
transformations, these methods are only converted when called with parentheses:
a.keys # => a.keys (no conversion - could be property access)
a.keys() # => Object.keys(a) (converted - clearly a method call)
The following methods require parentheses for automatic conversion:
keys, values, entries, index, rindex, clear, reverse!, max, min
To force conversion even without parentheses, explicitly include the method:
Ruby2JS.convert('a.keys', include: [:keys]) # => Object.keys(a)
Or use include_all: true to enable conversion for all such methods:
Ruby2JS.convert('a.keys', include_all: true) # => Object.keys(a)
Methods Requiring Explicit Inclusion
The following mappings will only be done if explicitly included
(pass include: [:class, :call] as a convert option to enable):
.class.constructora.calla()