OpalProxy
Opal Proxy provides a dynamic interface to JavaScript objects in Opal, allowing seamless property access, method calls, and Promise handling using idiomatic Ruby syntax.
Installation
Add this line to your Gemfile:
gem 'opal_proxy'
Execute:
bundle install
Document example
require "js/proxy"
class Document < JSProxy
def initialize
super($$.document)
end
end
document = Document.new
headers = document.querySelectorAll("h1") # or query_selector_all
headers.each do |h1|
h1.text_content = "Opal is great!" # or textContent
end
document.body.style.background_color = "lightblue"
document.body.style.font_family = "Arial, sans-serif"
document.body.style.color = "darkblue"
Window example
require "js/proxy"
# ... including document
class Window < JSProxy
def initialize
super($$.window)
end
end
window = Window.new
window.alert "Hello world!"
window.set_timeout(-> {
puts "1. Timeout test OK (1s delay)"
}, 1000)
window.fetch("https://jsonplaceholder.typicode.com/todos/1")
.then { |response| response.json }
.then do |data|
puts "5. Fetched: #{data["title"]}"
document.get_element_by_id("output").inner_html += "<p>5. Fetched: #{data["title"]}</p>"
end
.catch { |error| warn error["message"] }
Promise callbacks automatically unwrap returned JS::Proxy and JS::Promise values,
so native Promise flattening works across chained then, catch, and finally calls.
Interop behavior
Property lookup tries the original name first, then camelCase and common JavaScript
acronyms such as HTML, URL, and URI. For example, both inner_html and
document_uri map to their DOM equivalents.
JavaScript properties that collide with Ruby methods can always be accessed with []:
proxy["count"]
proxy["class"]
When a Ruby block is passed to a JavaScript method, it is appended as the final callback
argument. The callback receives its JavaScript this value first, followed by the native
callback arguments, all wrapped when necessary:
target.add_event_listener("click") do |receiver, event|
event.prevent_default
puts receiver
end
JS::Proxy is enumerable for JavaScript iterable and array-like objects, including
arrays, Set, Map, NodeList, and objects with numeric indexes and a length.
JQuery example
require "js/proxy"
# ... including document
doc = Document.new
jquery_script = doc.createElement('script')
jquery_script.src = "https://code.jquery.com/jquery-3.7.1.min.js"
doc.head.appendChild(jquery_script)
jquery_script.onload = -> {
class JQuery < JS::Proxy
def initialize(node)
super(`$(node)`)
end
end
document = JQuery.new($$.document)
document.ready do
paragraph = doc.createElement('p')
paragraph.text_content = "If you click on me, I will disappear."
doc.body.appendChild(paragraph)
JQuery.new("p").click(&:hide)
end
}
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/josephschito/opal_proxy.
License
The gem is available as open source under the terms of the MIT License.