We have released Opal v1.3.0 a week ago and today we are releasing Opal v1.3.1 containing a few last minute fixes. We plan Opal v1.3 to be supported with a best-effort principle for a longer term, backporting bugfixes.
This is quite a big release with a special focus on developer tools and error reporting improvements.
Preliminary ES Modules support
Although we didn't yet fully integrate with Webpack as originally planned, Jan Biedermann (of the Isomorfeus project) contributed some preliminary ES Modules support.
If you use Isomorfeus you can take advantage of it with its ESBuild integration and the newly added autoload hooks, which finally works without requiring a patched version of Opal.
If you don't use it you can still roll your own integration, making autoload dynamically fetch modules from the server as they're imported.
We are planning to work on a proper
import and npm package support for the next release, along with Ruby 3.1 support.
Newly supported language features
We already support a lot of Ruby 3.0 features. This release fills a few missing gaps, most of which will only be used in very niche usecases.
Refinements are now mostly supported. If you don't like monkey patching, this feature can improve your codebase.
Binding allows you to take a peek at local variables in a given scope. You probably most likely know it for
binding.pry - while we don't support those yet, it's now only a matter of time when it gets implemented - all prerequisites are there already.
Autoload statements will cause a file to be included inside your Opal bundle, but won't load it instantly. We moved a bigger deal of corelib to benefit from faster load times.
This support can also be used to load files dynamically, like
opal-zeitwerk does in Isomorfeus.
The following code used to call a super function with
(a,b,c) arguments, now it correctly calls it with
(4,b,c). Also a few more edge cases were corrected.
def method(a,b,c) a = 4 super end
We have now a larger synchronous IO support.
gets is implemented on a browser via
prompt (aka that annoying alert popup with a text field), on other platforms, including headless chrome, it bridges
Reminder: for basic support of other platforms than browser, you need to
require "opal/platform". For extended support of NodeJS, you need to
$ opal -ropal/platform -e 'p gets' 123 "123\n"
gets is all that's needed to make a runner able to be ran in the REPL mode
Global variable aliases
Certainly a lesser known feature of Ruby. Did you know it's possible to write this:
alias $PROGRAM_NAME $0 $PROGRAM_NAME = "abc" # This changes $0 as well!
Opal has you covered.
This Perl-inspired feature was almost removed in Ruby 3.0. But due to some interest, it was actually fixed. Opal now supports this as well! Have you never heard of this feature? That's fair, it mostly isn't present in production code, but can be used for writing unreadable code like this:
a=b=c=(1..100).each do |num| print num, ?\r, ("Fizz" unless (a = !a) .. (a = !a)), ("Buzz" unless (b = !b) ... !((c = !c) .. (c = !c))), ?\n end
opal-repl command line tool gained a number of improvements:
- Windows support
- Colored output
- Support for printing native JS Objects / null / undefined
- Support for everything that opal command line tool supports
- Support for multiple runners: nodejs, chrome, gjs, quickjs, miniracer (used to be miniracer only)
$ opal-repl >> ls 123 Comparable#methods: between? clamp Numeric#methods: __coerced__ clone conj conjugate div dup i imag imaginary polar pretty_print pretty_print_cycle real real? rect rectangular step to_c to_json to_n Number#methods: % & * ** + +@ - -@ / < << <= <=> == === > >= >>  ^ __id__ abs abs2 allbits? angle anybits? arg bit_length ceil chr coerce denominator digits divmod downto eql? equal? even? fdiv finite? floor gcd gcdlcm infinite? inspect instance_of? integer? is_a? kind_of? lcm magnitude modulo nan? negative? next nobits? nonzero? numerator object_id odd? ord phase positive? pow pred quo rationalize remainder round size succ times to_f to_i to_int to_r to_s truncate upto zero? | ~ >> $ opal-repl -Rchrome >> require 'native' => true >> $$[:navigator][:userAgent] => "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/95.0.4638.54 Safari/537.36" >>
Runners are how you can use different environments to run Opal code on, using our
opal command line tool. We added support for 3 new runners:
miniracer- Ruby bindings to pure V8 (used to be supported only for repl)
$ opal -ropal/platform -Rchrome -e 'p OPAL_PLATFORM' "headless-chrome" $ opal -ropal/platform -Rnodejs -e 'p OPAL_PLATFORM' "nodejs" $ opal -ropal/platform -Rgjs -e 'p OPAL_PLATFORM' "gjs" $ opal -ropal/platform -Rquickjs -e 'p OPAL_PLATFORM' "quickjs" $ opal -ropal/platform -Rminiracer -e 'p OPAL_PLATFORM' "opal-miniracer"
While the support for those is preliminary and works only with
stdio, there is a possibility to extend those implementations when needed (patches welcome!). GJS is now one of the primary GNOME development platforms, powering software like Flatseal, allowing you to bridge all GNOME libraries, like Glib or GTK4 (making it a fully featured Node.js alternative, though much more low level and a lot less popular - but that's a digression).
Source map debugger
We have improved the source map support in this release. It should now much more accurately tell you which line/column is being executed. Which means - easier debugging! And that's not all, if source mapping goes wrong, you can always use our new source map debugging tool:
Sprockets doesn't use
Opal::Builder - it has its own cache, though it may need to be configured.
Upgrade to Opal 1.3 and forget the long compilation times when using
opal command line tool or
Opal::Builder thru any other means (like
Opal::SimpleServer). This is implemented by caching the marshaled Compiler objects.
4x improvement for a simple script:
$ time opal _1.2.0_ -e 'p 123' 123 real 0m2.321s user 0m2.213s sys 0m0.107s $ time opal _1.3.0_ -e 'p 123' 123 real 0m0.537s user 0m0.450s sys 0m0.090s
8x when including more core, e.g.
$ time opal _1.2.0_ -ropal-parser -e 'p eval("(0..1)")' Object freezing is not supported by Opal 0..1 real 0m12.555s user 0m12.250s sys 0m0.349s $ time opal _1.3.0_ -ropal-parser -e 'p eval("(0..1)")' Object freezing is not supported by Opal 0..1 real 0m1.512s user 0m1.405s sys 0m0.249s
This big feature is experimental, and may totally change in future releases of Opal.
This complements the
PromiseV2 feature introduced in Opal v1.2 and uses magic comments and a supported library (aptly named
Check it out:
# await: sleep require "await" puts "Let's wait 2 seconds..." sleep 2 puts "Done!"
Please consult documentation of this feature: https://opalrb.com/docs/guides/v1.3.0/async
We are leaving this as experimental, because, as an Opal specific feature. Although it's not supported by Ruby itself the syntax is fully compatible, maybe some unexpected breakthrough will happen, with a port to a gem or to the language itself.
If you are adventurous, why not try Opal? You may be surprised how ready it is for your usecase! :D