Pragma
The Pragma filter provides line-level control over JavaScript output through special comments. This allows fine-grained customization of the transpilation on a per-line basis.
Pragmas are specified with a comment at the end of a line using the format:
# Pragma: <name>
Available Pragmas
?? (or nullish)
Forces the use of nullish coalescing (??) instead of logical or (||).
This is useful when you want to distinguish between null/undefined and
falsy values like 0, "", or false.
a ||= b # Pragma: ??
# => a ??= b
x = value || default # Pragma: ??
# => let x = value ?? default
Requirements: ES2020 for ??, ES2021 for ??=
When to use: jQuery/DOM APIs often return null or undefined but valid
values could be falsy (e.g., 0 for an index). Use this pragma when you need
nullish semantics.
|| (or logical)
Forces the use of logical or (||) instead of nullish coalescing (??).
This is the inverse of the ?? pragma. It’s useful when you’re using the
or: :nullish or or: :auto options globally but need logical || behavior
for a specific line where the value could legitimately be false.
enabled ||= true # Pragma: logical
# => enabled ||= true (not ??=)
x = flag || default # Pragma: ||
# => let x = flag || default (not ??)
When to use: When a variable can hold false as a valid value and you
want the fallback to execute for false, not just null/undefined. For
example, boolean flags where false should trigger the default assignment.
noes2015 (or function)
Forces traditional function syntax instead of arrow functions.
Arrow functions lexically bind this, which is often desirable. However,
DOM event handlers and jQuery callbacks typically need dynamic this binding
to reference the element that triggered the event.
element.on("click") { handle_click(this) } # Pragma: noes2015
# => element.on("click", function() {handle_click(this)})
items.each { |item| process(item) } # Pragma: function
# => items.each(function(item) {process(item)})
Without the pragma:
items.each { |item| process(item) }
# => items.each(item => process(item))
When to use: jQuery event handlers, DOM callbacks, or any situation where
you need this to refer to the calling context rather than the lexical scope.
guard
Ensures splat arrays return an empty array when the source is null or
undefined.
In Ruby, [*nil] returns []. In JavaScript, spreading null throws an error.
This pragma guards against that by using nullish coalescing.
[*items] # Pragma: guard
# => items ?? []
[1, *items, 2] # Pragma: guard
# => [1, ...items ?? [], 2]
Requirements: ES2020 (for ??)
When to use: When working with data from external APIs or DOM methods that
might return null, and you want to safely spread the result into an array.
skip
Removes statements from the JavaScript output entirely. Works with:
requireandrequire_relativestatements- Method definitions (
def) - Class method definitions (
def self.method) - Alias declarations (
alias) - Block structures:
if/unless,begin,while/until,case
This is useful when a Ruby file contains code that shouldn’t be included in the JavaScript output (e.g., Ruby-specific methods, native Ruby gems, runtime dependencies that will be provided separately).
require 'prism' # Pragma: skip
# => (no output)
require_relative 'helper' # Pragma: skip
# => (no output)
def respond_to?(method) # Pragma: skip
# Ruby-only method, not needed in JS
true
end
# => (no output)
def self.===(other) # Pragma: skip
# Ruby-only class method
other.is_a?(Node)
end
# => (no output)
alias loc location # Pragma: skip
# => (no output)
unless defined?(RUBY2JS_SELFHOST) # Pragma: skip
require 'parser/current'
# Ruby-only code block
end
# => (no output - entire block removed)
require 'my_module' # No pragma, will be processed normally
# => import ... (if ESM filter is active)
When to use:
- When transpiling Ruby code that requires external dependencies provided separately in the JavaScript environment
- When using the
requirefilter and you need to exclude specific requires from bundling - When Ruby source files contain methods that are Ruby-specific and have no
JavaScript equivalent (e.g.,
respond_to?,is_a?,to_sexp) - When removing Ruby metaprogramming methods that don’t translate to JavaScript
Type Disambiguation Pragmas
Some Ruby methods have different JavaScript equivalents depending on the receiver type. These pragmas let you specify the intended type.
array
Specifies that the receiver is an Array.
arr.dup # Pragma: array
# => arr.slice()
arr << item # Pragma: array
# => arr.push(item)
When to use: When Ruby2JS can’t infer the type and you need array-specific behavior.
hash
Specifies that the receiver is a Hash (JavaScript object).
obj.dup # Pragma: hash
# => {...obj}
obj.include?(key) # Pragma: hash
# => key in obj
When to use: When you need hash-specific operations like the in operator
for key checking.
set
Specifies that the receiver is a Set.
s << item # Pragma: set
# => s.add(item)
s.include?(item) # Pragma: set
# => s.has(item)
When to use: When working with JavaScript Set objects. Ruby’s Set#<<
becomes .push() by default (array behavior), and Set#include? becomes
.includes(). Use this pragma to get the correct Set methods: .add() and
.has().
string
Specifies that the receiver is a String.
str.dup # Pragma: string
# => str
Note: Strings in JavaScript are immutable, so .dup is a no-op.
Behavior Pragmas
These pragmas modify how specific Ruby patterns translate to JavaScript.
method
Converts .call() to direct invocation for function objects.
fn.call(x, y) # Pragma: method
# => fn(x, y)
When to use: When working with first-class functions stored in variables
that need to be invoked directly rather than using .call().
proto
Converts .class to .constructor for JavaScript prototype access.
obj.class # Pragma: proto
# => obj.constructor
When to use: When you need to access the JavaScript constructor function
rather than a literal .class property.
entries
Converts hash iteration to use Object.entries().
hash.each { |k, v| process(k, v) } # Pragma: entries
# => Object.entries(hash).forEach(([k, v]) => process(k, v))
When to use: When iterating over JavaScript objects where you need both
keys and values, and the standard .each translation doesn’t apply.
Usage Notes
Case Insensitivity
Pragma names are case-insensitive:
x = a || b # PRAGMA: ??
x = a || b # pragma: ??
x = a || b # Pragma: ??
# All produce: let x = a ?? b
Multiple Pragmas
You can use multiple pragmas on the same line, and they will all be applied:
# Both logical and method pragmas apply
x ||= fn.call(y) # Pragma: logical # Pragma: method
# => x ||= fn(y)
# Nullish and method together
x ||= fn.call(y) # Pragma: ?? # Pragma: method
# => x ??= fn(y)
You can also use different pragmas on different lines:
options ||= {} # Pragma: ??
element.on("click") { handle(this) } # Pragma: noes2015
Filter Loading
The pragma filter is automatically loaded when you require it:
require 'ruby2js/filter/pragma'
Or specify it in your configuration:
Ruby2JS.convert(code, filters: [Ruby2JS::Filter::Pragma])
Combining with Other Filters
The pragma filter works alongside other filters. It automatically reorders
itself to run before the Functions and ESM filters, ensuring pragmas like
skip, entries, and method are processed correctly regardless of the
order filters are specified.
Background
The pragma filter was inspired by the need to handle edge cases in real-world JavaScript frameworks. When interfacing with existing JavaScript libraries, particularly jQuery and DOM APIs, Ruby2JS’s default output may not always produce the desired semantics.
Rather than changing global behavior, pragmas provide targeted control exactly where needed, keeping the rest of your code using standard Ruby2JS conventions.