It's been almost a year from our 0.6.0 release and has been an awesome time for the Opal community. Today I'm proud to announce we have released v0.7.0, which comes packed with lots of good stuff and uncountable bug fixes.
#require #require_relative and #require_tree
The require system has been completely overhauled in Opal 0.7. The previous version was a rather smart wrapper around sprockets directives but had some limitations, especially when it came to interleaving require calls and code. Some gems couldn't be compiled with Opal just for that reason.
The new require system now relies on a module repository where each "module" actually corresponds to a Ruby file compiled with Opal. This means that #require
calls aren't no-ops anymore.
In addition to that #require_relative
support has been added and for feature parity with sprockets directives we're also introducing #require_tree
. The latter will be particularly useful to require templates.
Keyword Arguments
This has been a super requested feature, and thanks to Adam Beynon they're now a reality. They still have some rough edges (as they did in their first CRuby/MRI incarnation) but the core is there for you all to enjoy.
Documentation
Soooo it's Ruby baby, not Python. We write tests, not docs…
That's true, but as a project grows docs become more and more useful. Luckily most of our codebase mirrors CRuby/MRI thus making superfluous (and unpractical) to re-document every single method, but that is enough just 80% of the time. In fact I found myself asking many times if a specific method was already implemented and whether it had any deviation in semantics or any known bug.
You can now find docs for both corelib and stdlib on the Opal website.
(I'll update docs and CDN links to point to the new stable release v0.7 in the next few days)
Testing
We've added almost 600 new specs (+15%) from RubySpec to our suite, which is great, but the recent "drama" around the project lead me to give another look at tests embedded into our beloved CRuby.
A slightly adapted* version of the latest Minitest is now part of the stdlib, and a super simplified test/unit
adapter has been re-implemented. Opal test suite now runs the amazing number of 1 (!) test from the original CRuby suite. As you may have imagined at this point, more will come.
* adaptation was mostly related to thread usage
Hash now calls #hash on keys, but optimizes for String
Full support for #hash
has been added to Hash
where previously .toString()
was called internally by JavaScript. That worked surprisingly well, but there were edge cases (using the number 2 or the string "2" as key would have yielded the same value).
The only exception to the new behavior are Strings (and Symbols) that have a separate hash table (a JavaScript object) and are used as keys directly. This allows for a super-optimized common case while retaining good semantics for edge cases and also allows a to have an internal representation of the Hash that is just a JS object.
objects don't let objects be casted
#method_missing now works for bridged classes too
As you probably already know most core classes in Opal are bridged directly from JavaScript. The list includes Array, Boolean, Numeric, String, Proc, Exception, Regexp and Time. Of course having custom classes inheriting from a native constructor is super easy:
`function MyJSClass() { this.foo = "bar"; this.baz = "qux" }`
class MyClass < `MyJSClass`
# this.foo in JS equals to @foo in Opal
attr_reader :foo
def method_missing name, *a, &b
`return this[#{name}]`
end
end
MyClass.new.foo #=> "bar"
MyClass.new.baz #=> "qux"
That's how opal-jquery is implemented. Unfortunately those classes until now were lacking #method_missing
support.
How cool it is that Opal has had method_missing
for all this time on normal classes? You can still hear people in awe discovering that, what a great pleasure! :)
Node.js builtin support
Node.js is a fantastic platform to have fun of and in the past I had my personal share. But the fact is that stuff like NodeWebkit (now NW.js) or AtomShell are really good if you want to build a desktop app reusing all of you web development super powers. Turns out it's also handy to run Opal specs.
Starting with Opal 0.7 stdlib features platform specific additions for Node.js that perfect support for IO, File, Dir, ENV, and much more, including Kernel#node_require
. To run code on Node.js from the command line with these additions you just require 'nodejs'
in your code or as a CLI option:
$ opal -rnodejs -e 'p Dir["lib/*"]' # requires npm install -g glob
["lib/mspec", "lib/opal", "lib/opal.rb"]
Improved CLI
The Command Line Interface has been further improved and replicates most options found on the CRuby/MRI CLI plus others that are specific or just useful in out nutty JavaScript land, here's what it looks like now:
$ opal -h
Usage: opal [options] -- [programfile]
-v print version number, then turn on verbose mode
--verbose turn on verbose mode
--version Print the version
-h, --help Show this message
Basic Options:
-I, --include DIR Append a load path (may be used more than once)
-e, --eval SOURCE One line of script. Several -e's allowed. Omit [programfile]
-r, --require LIBRARY Require the library before executing your script
-s, --stub FILE Stubbed files will be compiled as empty files
-p, --preload FILE Preloaded files will be prepared for dynamic requires
-g, --gem GEM_NAME Adds the specified GEM_NAME to Opal's load path.
Running Options:
--sexp Show Sexps
-m, --map Show sourcemap
-c, --compile Compile to JavaScript
-R, --runner RUNNER Choose the runner: nodejs (default), server
--server-port PORT Set the port for the server runner (default port: 3000)
Compilation Options:
-M, --no-method-missing Enable/Disable method missing
-O, --no-opal Enable/Disable implicit `require "opal"`
-A, --arity-check Enable arity check
-V Enable inline Operators
-D, --dynamic-require LEVEL Set level of dynamic require severity.
(deafult: error, values: error, warning, ignore)
-P, --source-map [FILE] Enable/Disable source map
-F, --file FILE Set filename for compiled code
--irb Enable IRB var mode
Lots of fixes and internal stuff
I can say that working on Opal internals is much better now. Things are still improving towards an even more precise matching of Ruby semantics.
Let me take a moment to thank again and publicly Adam Beynon for creating Opal, meh for being so wonderfully stubborn in respecting Ruby semantics and for his gigantic gargantuan work on the stdlib and–finally–all the other contributors, the users and the library builders.