opal 0.5.5 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +40 -9
- data/CHANGELOG.md +349 -0
- data/Gemfile +7 -8
- data/README.md +25 -3
- data/Rakefile +4 -2
- data/bin/opal +1 -1
- data/examples/rack/Gemfile +3 -0
- data/examples/rack/app/application.rb +13 -0
- data/examples/rack/app/user.rb +21 -0
- data/examples/rack/config.ru +7 -0
- data/examples/rack/index.html.erb +10 -0
- data/examples/sinatra/Gemfile +4 -0
- data/examples/sinatra/app/application.rb +7 -0
- data/examples/sinatra/config.ru +21 -0
- data/lib/mspec/opal/rake_task.rb +29 -8
- data/lib/mspec/opal/runner.rb +5 -4
- data/lib/opal.rb +1 -0
- data/lib/opal/builder.rb +0 -28
- data/lib/opal/cli.rb +0 -14
- data/lib/opal/compiler.rb +12 -11
- data/lib/opal/fragment.rb +8 -1
- data/lib/opal/nodes/array.rb +1 -1
- data/lib/opal/nodes/base.rb +4 -0
- data/lib/opal/nodes/call.rb +6 -2
- data/lib/opal/nodes/call_special.rb +1 -1
- data/lib/opal/nodes/class.rb +2 -2
- data/lib/opal/nodes/constants.rb +3 -1
- data/lib/opal/nodes/helpers.rb +23 -14
- data/lib/opal/nodes/if.rb +16 -9
- data/lib/opal/nodes/literal.rb +37 -5
- data/lib/opal/nodes/logic.rb +7 -1
- data/lib/opal/nodes/module.rb +2 -2
- data/lib/opal/nodes/scope.rb +13 -2
- data/lib/opal/nodes/top.rb +9 -0
- data/lib/opal/nodes/variables.rb +5 -2
- data/lib/opal/parser.rb +306 -71
- data/lib/opal/parser/grammar.rb +2667 -2775
- data/lib/opal/parser/grammar.y +177 -233
- data/lib/opal/parser/lexer.rb +511 -427
- data/lib/opal/parser/sexp.rb +15 -3
- data/lib/opal/source_map.rb +8 -4
- data/lib/opal/sprockets.rb +4 -0
- data/lib/opal/sprockets/cache_key_fix.rb +17 -0
- data/lib/opal/sprockets/environment.rb +21 -0
- data/lib/opal/sprockets/erb.rb +30 -0
- data/lib/opal/sprockets/processor.rb +127 -0
- data/lib/opal/sprockets/server.rb +166 -0
- data/lib/opal/util.rb +29 -0
- data/lib/opal/version.rb +1 -1
- data/opal.gemspec +1 -1
- data/opal/corelib/array.rb +106 -187
- data/opal/corelib/array/inheritance.rb +113 -0
- data/opal/corelib/basic_object.rb +6 -2
- data/opal/corelib/boolean.rb +4 -0
- data/opal/corelib/class.rb +2 -0
- data/opal/corelib/complex.rb +3 -0
- data/opal/corelib/enumerable.rb +75 -8
- data/opal/corelib/enumerator.rb +2 -0
- data/opal/corelib/error.rb +23 -23
- data/opal/corelib/hash.rb +5 -5
- data/opal/corelib/helpers.rb +51 -16
- data/opal/corelib/io.rb +7 -24
- data/opal/corelib/kernel.rb +23 -11
- data/opal/corelib/module.rb +44 -47
- data/opal/corelib/nil_class.rb +4 -0
- data/opal/corelib/numeric.rb +101 -15
- data/opal/corelib/range.rb +2 -0
- data/opal/corelib/rational.rb +3 -0
- data/opal/corelib/regexp.rb +36 -17
- data/opal/corelib/runtime.js +22 -7
- data/opal/corelib/string.rb +213 -110
- data/opal/corelib/string/inheritance.rb +78 -0
- data/opal/corelib/struct.rb +8 -0
- data/opal/corelib/time.rb +54 -42
- data/opal/corelib/variables.rb +24 -0
- data/opal/opal.rb +5 -27
- data/spec/cli/compiler_spec.rb +136 -0
- data/spec/cli/dependency_resolver_spec.rb +40 -0
- data/spec/cli/lexer_spec.rb +110 -0
- data/spec/cli/parser/alias_spec.rb +26 -0
- data/spec/cli/parser/and_spec.rb +13 -0
- data/spec/cli/parser/attrasgn_spec.rb +28 -0
- data/spec/cli/parser/begin_spec.rb +42 -0
- data/spec/cli/parser/block_spec.rb +12 -0
- data/spec/cli/parser/break_spec.rb +17 -0
- data/spec/cli/parser/call_spec.rb +139 -0
- data/spec/cli/parser/class_spec.rb +35 -0
- data/spec/cli/parser/comments_spec.rb +11 -0
- data/spec/cli/parser/def_spec.rb +61 -0
- data/spec/cli/parser/if_spec.rb +26 -0
- data/spec/cli/parser/iter_spec.rb +59 -0
- data/spec/cli/parser/lambda_spec.rb +64 -0
- data/spec/cli/parser/literal_spec.rb +113 -0
- data/spec/cli/parser/masgn_spec.rb +37 -0
- data/spec/cli/parser/module_spec.rb +27 -0
- data/spec/cli/parser/not_spec.rb +27 -0
- data/spec/cli/parser/op_asgn1_spec.rb +23 -0
- data/spec/cli/parser/op_asgn2_spec.rb +23 -0
- data/spec/cli/parser/or_spec.rb +13 -0
- data/spec/cli/parser/return_spec.rb +17 -0
- data/spec/cli/parser/sclass_spec.rb +21 -0
- data/spec/cli/parser/string_spec.rb +269 -0
- data/spec/cli/parser/super_spec.rb +20 -0
- data/spec/cli/parser/undef_spec.rb +15 -0
- data/spec/cli/parser/unless_spec.rb +13 -0
- data/spec/cli/parser/variables_spec.rb +92 -0
- data/spec/cli/parser/while_spec.rb +15 -0
- data/spec/cli/parser/yield_spec.rb +20 -0
- data/spec/cli/spec_helper.rb +31 -11
- data/spec/opal/core/array/set_range_to_array_spec.rb +7 -0
- data/spec/opal/core/date_spec.rb +122 -0
- data/spec/opal/core/language/predefined_spec.rb +1 -1
- data/spec/opal/core/runtime/operator_call_spec.rb +13 -0
- data/spec/opal/core/runtime/truthy_spec.rb +23 -0
- data/spec/opal/filters/bugs/array.rb +96 -87
- data/spec/opal/filters/bugs/basic_object.rb +9 -0
- data/spec/opal/filters/bugs/class.rb +16 -0
- data/spec/opal/filters/bugs/enumerable.rb +54 -0
- data/spec/opal/filters/bugs/language.rb +37 -3
- data/spec/opal/filters/bugs/math.rb +93 -0
- data/spec/opal/filters/bugs/nil.rb +7 -0
- data/spec/opal/filters/bugs/numeric.rb +19 -0
- data/spec/opal/filters/bugs/opal.rb +12 -0
- data/spec/opal/filters/bugs/regexp.rb +0 -2
- data/spec/opal/filters/bugs/string.rb +317 -19
- data/spec/opal/filters/bugs/struct.rb +29 -0
- data/spec/opal/filters/bugs/time.rb +130 -9
- data/spec/opal/filters/unsupported/encoding.rb +52 -4
- data/spec/opal/filters/unsupported/enumerator.rb +0 -3
- data/spec/opal/filters/unsupported/integer_size.rb +7 -0
- data/spec/opal/filters/unsupported/method_added.rb +10 -0
- data/spec/opal/filters/unsupported/mutable_strings.rb +299 -1
- data/spec/opal/filters/unsupported/private_constants.rb +30 -0
- data/spec/opal/filters/unsupported/private_methods.rb +16 -0
- data/spec/opal/filters/unsupported/random.rb +4 -0
- data/spec/opal/filters/unsupported/tainted.rb +53 -0
- data/spec/opal/filters/unsupported/trusted.rb +5 -0
- data/spec/opal/rubyspecs +167 -234
- data/spec/opal/spec_helper.rb +3 -0
- data/spec/opal/stdlib/promise/error_spec.rb +15 -0
- data/spec/opal/stdlib/promise/rescue_spec.rb +35 -0
- data/spec/opal/stdlib/promise/then_spec.rb +54 -0
- data/spec/opal/stdlib/promise/trace_spec.rb +35 -0
- data/spec/opal/stdlib/promise/value_spec.rb +15 -0
- data/spec/opal/stdlib/promise/when_spec.rb +34 -0
- data/stdlib/base64.rb +152 -0
- data/stdlib/date.rb +82 -49
- data/{opal/corelib → stdlib}/encoding.rb +3 -1
- data/stdlib/erb.rb +0 -1
- data/stdlib/json.rb +10 -26
- data/stdlib/math.rb +370 -0
- data/stdlib/native.rb +40 -33
- data/stdlib/opal-parser.rb +7 -4
- data/stdlib/promise.rb +292 -0
- data/stdlib/strscan.rb +1 -1
- data/stdlib/template.rb +1 -3
- data/stdlib/time.rb +9 -0
- metadata +143 -204
- data/doc/compiler.md +0 -42
- data/doc/compiler_options.md +0 -5
- data/doc/examples/node_http_server.rb +0 -49
- data/doc/external_libraries.md +0 -9
- data/doc/generated_javascript.md +0 -272
- data/doc/home.md +0 -17
- data/doc/method_missing.md +0 -58
- data/doc/static_applications.md +0 -60
- data/doc/using_ruby_from_javascript.md +0 -18
- data/doc/using_sprockets.md +0 -65
- data/spec/opal/core/numeric/abs_spec.rb +0 -12
- data/spec/opal/core/numeric/downto_spec.rb +0 -19
- data/spec/opal/core/numeric/equal_value_spec.rb +0 -9
- data/spec/opal/core/numeric/even_spec.rb +0 -21
- data/spec/opal/core/numeric/magnitude_spec.rb +0 -12
- data/spec/opal/core/numeric/odd_spec.rb +0 -21
- data/spec/opal/core/string/chop_spec.rb +0 -10
- data/spec/opal/core/string/chr_spec.rb +0 -13
- data/spec/opal/core/string/clone_spec.rb +0 -8
- data/spec/opal/core/string/comparison_spec.rb +0 -13
- data/spec/opal/core/string/dup_spec.rb +0 -8
- data/spec/opal/core/string/element_reference_spec.rb +0 -96
- data/spec/opal/core/string/fixtures/classes.rb +0 -49
- data/spec/opal/core/string/format_spec.rb +0 -9
- data/spec/opal/core/string/freeze_spec.rb +0 -15
- data/spec/opal/core/string/gsub_spec.rb +0 -31
- data/spec/opal/core/string/lines_spec.rb +0 -9
- data/spec/opal/core/string/ljust_spec.rb +0 -32
- data/spec/opal/core/string/lstrip_spec.rb +0 -7
- data/spec/opal/core/string/match_spec.rb +0 -49
- data/spec/opal/core/string/next_spec.rb +0 -10
- data/spec/opal/core/string/ord_spec.rb +0 -9
- data/spec/opal/core/string/partition_spec.rb +0 -10
- data/spec/opal/core/string/rindex_spec.rb +0 -50
- data/spec/opal/core/string/rjust_spec.rb +0 -32
- data/spec/opal/core/string/rstrip_spec.rb +0 -7
- data/spec/opal/core/string/scan_spec.rb +0 -66
- data/spec/opal/core/string/slice_spec.rb +0 -74
- data/spec/opal/core/string/split_spec.rb +0 -5
- data/spec/opal/core/string/strip_spec.rb +0 -6
- data/spec/opal/core/string/sub_spec.rb +0 -38
- data/spec/opal/core/string/succ_spec.rb +0 -10
- data/spec/opal/core/string/sum_spec.rb +0 -5
- data/spec/opal/core/string/to_f_spec.rb +0 -14
- data/spec/opal/core/string/to_i_spec.rb +0 -25
- data/spec/opal/core/string/tr_s_spec.rb +0 -31
- data/spec/opal/core/string/tr_spec.rb +0 -31
- data/spec/opal/filters/bugs/parser.rb +0 -10
- data/spec/opal/filters/unsupported/immutable_strings.rb +0 -24
- data/spec/opal/filters/unsupported/string_subclasses.rb +0 -8
- data/spec/opal/parser/alias_spec.rb +0 -26
- data/spec/opal/parser/and_spec.rb +0 -13
- data/spec/opal/parser/array_spec.rb +0 -22
- data/spec/opal/parser/attrasgn_spec.rb +0 -28
- data/spec/opal/parser/begin_spec.rb +0 -42
- data/spec/opal/parser/block_spec.rb +0 -12
- data/spec/opal/parser/break_spec.rb +0 -17
- data/spec/opal/parser/call_spec.rb +0 -131
- data/spec/opal/parser/class_spec.rb +0 -35
- data/spec/opal/parser/const_spec.rb +0 -13
- data/spec/opal/parser/cvar_spec.rb +0 -11
- data/spec/opal/parser/def_spec.rb +0 -61
- data/spec/opal/parser/false_spec.rb +0 -17
- data/spec/opal/parser/file_spec.rb +0 -7
- data/spec/opal/parser/gvar_spec.rb +0 -13
- data/spec/opal/parser/hash_spec.rb +0 -17
- data/spec/opal/parser/heredoc_spec.rb +0 -30
- data/spec/opal/parser/iasgn_spec.rb +0 -9
- data/spec/opal/parser/if_spec.rb +0 -26
- data/spec/opal/parser/int_spec.rb +0 -13
- data/spec/opal/parser/iter_spec.rb +0 -59
- data/spec/opal/parser/ivar_spec.rb +0 -9
- data/spec/opal/parser/lambda_spec.rb +0 -64
- data/spec/opal/parser/lasgn_spec.rb +0 -8
- data/spec/opal/parser/line_spec.rb +0 -8
- data/spec/opal/parser/lvar_spec.rb +0 -38
- data/spec/opal/parser/masgn_spec.rb +0 -37
- data/spec/opal/parser/module_spec.rb +0 -27
- data/spec/opal/parser/nil_spec.rb +0 -17
- data/spec/opal/parser/not_spec.rb +0 -27
- data/spec/opal/parser/nth_ref_spec.rb +0 -13
- data/spec/opal/parser/op_asgn1_spec.rb +0 -23
- data/spec/opal/parser/op_asgn2_spec.rb +0 -23
- data/spec/opal/parser/or_spec.rb +0 -13
- data/spec/opal/parser/parse_spec.rb +0 -66
- data/spec/opal/parser/regexp_spec.rb +0 -16
- data/spec/opal/parser/return_spec.rb +0 -17
- data/spec/opal/parser/sclass_spec.rb +0 -21
- data/spec/opal/parser/self_spec.rb +0 -17
- data/spec/opal/parser/str_spec.rb +0 -107
- data/spec/opal/parser/string_spec.rb +0 -8
- data/spec/opal/parser/super_spec.rb +0 -20
- data/spec/opal/parser/true_spec.rb +0 -17
- data/spec/opal/parser/undef_spec.rb +0 -15
- data/spec/opal/parser/unless_spec.rb +0 -13
- data/spec/opal/parser/while_spec.rb +0 -15
- data/spec/opal/parser/xstr_spec.rb +0 -116
- data/spec/opal/parser/yield_spec.rb +0 -20
data/doc/compiler.md
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
# Opal Compiler
|
2
|
-
|
3
|
-
Opal is a source to source compiler. It accepts ruby code as a string and
|
4
|
-
generates javascript code which can be run in any environment. Generated
|
5
|
-
code relies on the opal runtime which provides the class system and some
|
6
|
-
other runtime helpers.
|
7
|
-
|
8
|
-
## Compiler stages
|
9
|
-
|
10
|
-
The compiler can be broken down into 3 separate stages:
|
11
|
-
|
12
|
-
* lexing
|
13
|
-
* parsing
|
14
|
-
* code generation
|
15
|
-
|
16
|
-
### Lexer
|
17
|
-
|
18
|
-
The [opal lexer](../lib/opal/parser/lexer.rb) is implemented in pure ruby using
|
19
|
-
the `StringScanner` class from the opal stdlib. The source code is scanned
|
20
|
-
and tokens are then provided to the parser. This process simply converts
|
21
|
-
the ruby code given as a string, into a list of tokens representing the
|
22
|
-
parts of the ruby code.
|
23
|
-
|
24
|
-
### Parser
|
25
|
-
|
26
|
-
The [opal parser](../lib/opal/parser/grammar.y) is implemented using a standard
|
27
|
-
bison like syntax, but relies on `racc`, a ruby implementation of yacc/bison
|
28
|
-
which is again available in the standard library. The parser takes these tokens
|
29
|
-
generated by the lexer and builds a syntax tree representing the ruby code.
|
30
|
-
This syntax tree is represented by [sexps](../lib/opal/parser/sexp.rb). As
|
31
|
-
ruby is such a complex and dynamic language, there is a lot of interaction
|
32
|
-
between the parser and the lexer, namely through a preserved `lex_state`.
|
33
|
-
|
34
|
-
### Code generation
|
35
|
-
|
36
|
-
The [opal compiler](../lib/opal/compiler.rb) takes these sexps from the parser
|
37
|
-
and generates ruby code from them. Each type of sexp has [its own node type](../lib/opal/nodes/base.rb)
|
38
|
-
used to generate javascript. Each node creates an array of one or more
|
39
|
-
[fragments](../lib/opal/fragment.rb) which are the concatendated together to
|
40
|
-
form the final javascript. Fragments are used as they contain the generated
|
41
|
-
code as well as a reference back to the original sexp which is useful for
|
42
|
-
generating source maps afterwards.
|
data/doc/compiler_options.md
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
# run with:
|
2
|
-
#
|
3
|
-
# bundle exec ./bin/opal ./doc/examples/node_http_server.rb
|
4
|
-
#
|
5
|
-
|
6
|
-
%x{
|
7
|
-
var http;
|
8
|
-
http = require('http');
|
9
|
-
}
|
10
|
-
|
11
|
-
|
12
|
-
module HTTP
|
13
|
-
class Server
|
14
|
-
%x{
|
15
|
-
var dom_class = http.Server;
|
16
|
-
#{self}['_proto'] = dom_class.prototype;
|
17
|
-
def = #{self}._proto;
|
18
|
-
dom_class.prototype._klass = #{self};
|
19
|
-
}
|
20
|
-
|
21
|
-
def self.__http__
|
22
|
-
Native(`http`)
|
23
|
-
end
|
24
|
-
|
25
|
-
alias_native :listen, :listen
|
26
|
-
|
27
|
-
def self.start options = {}, &block
|
28
|
-
host = options[:host] || '127.0.0.1'
|
29
|
-
port = options[:port] || 3000
|
30
|
-
|
31
|
-
server = __http__.createServer do |req, res|
|
32
|
-
req = Native(req)
|
33
|
-
res = Native(res)
|
34
|
-
status, headers, body = block.call(`req`)
|
35
|
-
res.writeHead(status, headers.to_n);
|
36
|
-
res.end(body.join(' '));
|
37
|
-
end
|
38
|
-
|
39
|
-
server.listen(port, host)
|
40
|
-
puts("Server running at http://#{host}:#{port}/");
|
41
|
-
server
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
util = Native(`require('util')`)
|
47
|
-
HTTP::Server.start port: 3000 do |env|
|
48
|
-
[200, {'Content-Type' => 'text/plain'}, ["Hello World!\n", util.inspect(env)]]
|
49
|
-
end
|
data/doc/external_libraries.md
DELETED
data/doc/generated_javascript.md
DELETED
@@ -1,272 +0,0 @@
|
|
1
|
-
# Generated Javascript
|
2
|
-
|
3
|
-
Opal is a source-to-source compiler, so there is no VM as such and the
|
4
|
-
compiled code aims to be as fast and efficient as possible, mapping
|
5
|
-
directly to underlying javascript features and objects where possible.
|
6
|
-
|
7
|
-
## Overview
|
8
|
-
|
9
|
-
ruby | javascript
|
10
|
-
-------------------------|---------------------------
|
11
|
-
`self` | `this`
|
12
|
-
`true` | `true`
|
13
|
-
`false` | `false`
|
14
|
-
`nil` | `nil`
|
15
|
-
`42` | `42`
|
16
|
-
`3.142` | `3.142`
|
17
|
-
`"hello"` | `"hello"`
|
18
|
-
`:world` | `"world"`
|
19
|
-
`[1, 2, 3]` | `[1, 2, 3]`
|
20
|
-
`{ "a" => 2, "b" => 4 }` | `$opal.hash("a", 2, "b", 4)`
|
21
|
-
`1..10` | `$opal.range(1, 10)`
|
22
|
-
`recv.foo` | `recv.$foo()`
|
23
|
-
`recv.bar(1, 2, 3)` | `recv.$bar(1, 2, 3)`
|
24
|
-
`recv.baz = 10` | `recv['$baz='](10)`
|
25
|
-
`a + b` | `a['$+'](b)`
|
26
|
-
|
27
|
-
## Literals
|
28
|
-
|
29
|
-
**self** is mostly compiled to `this`. Methods and blocks are implemented
|
30
|
-
as javascript functions, so their `this` value will be the right
|
31
|
-
`self` value. Class bodies and the top level scope use a `self` variable
|
32
|
-
to improve readability.
|
33
|
-
|
34
|
-
**true** and **false** are compiled directly into their native boolean
|
35
|
-
equivalents. This makes interaction a lot easier as there is no need
|
36
|
-
to convert values to opal specific values. It does mean that there is
|
37
|
-
only a `Boolean` ruby class available, not seperate `TrueClass` and
|
38
|
-
`FalseClass` classes.
|
39
|
-
|
40
|
-
**nil** is compiled to a `nil` javascript variable. `nil` is a real object
|
41
|
-
which allows methods to be called on it. Opal cannot send methods to `null`
|
42
|
-
or `undefined`, and they are considered bad values to be inside ruby code.
|
43
|
-
|
44
|
-
```ruby
|
45
|
-
nil # => nil
|
46
|
-
true # => true
|
47
|
-
false # => false
|
48
|
-
self # => self
|
49
|
-
```
|
50
|
-
|
51
|
-
##### Strings
|
52
|
-
|
53
|
-
Ruby strings are compiled directly into javascript strings for
|
54
|
-
performance as well as readability. This has the side effect that Opal
|
55
|
-
does not support mutable strings - i.e. all strings are immutable.
|
56
|
-
|
57
|
-
##### Symbols
|
58
|
-
|
59
|
-
For performance reasons, symbols compile directly into strings. Opal
|
60
|
-
supports all the symbol syntaxes, but does not have a real `Symbol`
|
61
|
-
class. Symbols and Strings can therefore be used interchangeably.
|
62
|
-
|
63
|
-
```ruby
|
64
|
-
"hello world!" # => "hello world!"
|
65
|
-
:foo # => "foo"
|
66
|
-
<<-EOS # => "\nHello there.\n"
|
67
|
-
Hello there.
|
68
|
-
EOS
|
69
|
-
```
|
70
|
-
|
71
|
-
##### Numbers
|
72
|
-
|
73
|
-
In Opal there is a single class for numbers; `Numeric`. To keep opal
|
74
|
-
as performant as possible, ruby numbers are mapped to native numbers.
|
75
|
-
This has the side effect that all numbers must be of the same class.
|
76
|
-
Most relevant methods from `Integer`, `Float` and `Numeric` are
|
77
|
-
implemented on this class.
|
78
|
-
|
79
|
-
```ruby
|
80
|
-
42 # => 42
|
81
|
-
3.142 # => 3.142
|
82
|
-
```
|
83
|
-
|
84
|
-
##### Arrays
|
85
|
-
|
86
|
-
Ruby arrays are compiled directly into javascript arrays. Special
|
87
|
-
ruby syntaxes for word arrays etc are also supported.
|
88
|
-
|
89
|
-
```ruby
|
90
|
-
[1, 2, 3, 4] # => [1, 2, 3, 4]
|
91
|
-
%w[foo bar baz] # => ["foo", "bar", "baz"]
|
92
|
-
```
|
93
|
-
|
94
|
-
##### Hash
|
95
|
-
|
96
|
-
Inside a generated ruby script, a function `__hash` is available which
|
97
|
-
creates a new hash. This is also available in javascript as `Opal.hash`
|
98
|
-
and simply returns a new instance of the `Hash` class.
|
99
|
-
|
100
|
-
```ruby
|
101
|
-
{ :foo => 100, :baz => 700 } # => __hash("foo", 100, "baz", 700)
|
102
|
-
{ foo: 42, bar: [1, 2, 3] } # => __hash("foo", 42, "bar", [1, 2, 3])
|
103
|
-
```
|
104
|
-
|
105
|
-
##### Range
|
106
|
-
|
107
|
-
Similar to hash, there is a function `__range` available to create
|
108
|
-
range instances.
|
109
|
-
|
110
|
-
```ruby
|
111
|
-
1..4 # => __range(1, 4, true)
|
112
|
-
3...7 # => __range(3, 7, false)
|
113
|
-
```
|
114
|
-
|
115
|
-
## Logic and conditionals
|
116
|
-
|
117
|
-
As per ruby, Opal treats only `false` and `nil` as falsy, everything
|
118
|
-
else is a truthy value including `""`, `0` and `[]`. This differs from
|
119
|
-
javascript as these values are also treated as false.
|
120
|
-
|
121
|
-
For this reason, most truthy tests must check if values are `false` or
|
122
|
-
`nil`.
|
123
|
-
|
124
|
-
Taking the following test:
|
125
|
-
|
126
|
-
```ruby
|
127
|
-
val = 42
|
128
|
-
|
129
|
-
if val
|
130
|
-
return 3.142;
|
131
|
-
end
|
132
|
-
```
|
133
|
-
|
134
|
-
This would be compiled into:
|
135
|
-
|
136
|
-
```javascript
|
137
|
-
var val = 42;
|
138
|
-
|
139
|
-
if (val !== false && val !== nil) {
|
140
|
-
return 3.142;
|
141
|
-
}
|
142
|
-
```
|
143
|
-
|
144
|
-
This makes the generated truthy tests (`if` statements, `and` checks and
|
145
|
-
`or` statements) a litle more verbose in the generated code.
|
146
|
-
|
147
|
-
## Instance variables
|
148
|
-
|
149
|
-
Instance variables in Opal work just as expected. When ivars are set or
|
150
|
-
retrieved on an object, they are set natively without the `@` prefix.
|
151
|
-
This allows real javascript identifiers to be used which is more
|
152
|
-
efficient then accessing variables by string name.
|
153
|
-
|
154
|
-
```ruby
|
155
|
-
@foo = 200
|
156
|
-
@foo # => 200
|
157
|
-
|
158
|
-
@bar # => nil
|
159
|
-
```
|
160
|
-
|
161
|
-
This gets compiled into:
|
162
|
-
|
163
|
-
```javascript
|
164
|
-
this.foo = 200;
|
165
|
-
this.foo; // => 200
|
166
|
-
|
167
|
-
this.bar; // => nil
|
168
|
-
```
|
169
|
-
|
170
|
-
## Interacting with javascript
|
171
|
-
|
172
|
-
Opal tries to interact as cleanly with javascript and its api as much
|
173
|
-
as possible. Ruby arrays, strings, numbers, regexps, blocks and booleans
|
174
|
-
are just javascript native equivalents. The only boxed core features are
|
175
|
-
hashes.
|
176
|
-
|
177
|
-
As most of the corelib deals with these low level details, opal provides
|
178
|
-
a special syntax for inlining javascript code. This is done with
|
179
|
-
x-strings or "backticks", as their ruby use has no useful translation
|
180
|
-
in the browser.
|
181
|
-
|
182
|
-
```ruby
|
183
|
-
`window.title`
|
184
|
-
# => "Opal: ruby to javascript compiler"
|
185
|
-
|
186
|
-
%x{
|
187
|
-
console.log("ruby version is:");
|
188
|
-
console.log(#{ OPAL_VERSION });
|
189
|
-
}
|
190
|
-
|
191
|
-
# => ruby version is:
|
192
|
-
# => 0.3.19
|
193
|
-
```
|
194
|
-
|
195
|
-
Even interpolations are supported, as seen here.
|
196
|
-
|
197
|
-
This feature of inlining code is used extensively, for example in
|
198
|
-
Array#length:
|
199
|
-
|
200
|
-
```ruby
|
201
|
-
class Array
|
202
|
-
def length
|
203
|
-
`this.length`
|
204
|
-
end
|
205
|
-
end
|
206
|
-
```
|
207
|
-
|
208
|
-
X-Strings also have the ability to automatically return their value,
|
209
|
-
as used by this example.
|
210
|
-
|
211
|
-
## Compiled Files
|
212
|
-
|
213
|
-
As described above, a compiled ruby source gets generated into a string
|
214
|
-
of javascript code that is wrapped inside an anonymous function. This
|
215
|
-
looks similar to the following:
|
216
|
-
|
217
|
-
```javascript
|
218
|
-
(function($opal) {
|
219
|
-
var $klass = $opal.klass, self = $opal.top;
|
220
|
-
// generated code
|
221
|
-
})(Opal);
|
222
|
-
```
|
223
|
-
|
224
|
-
As a complete example, assuming the following code:
|
225
|
-
|
226
|
-
```ruby
|
227
|
-
puts "foo"
|
228
|
-
```
|
229
|
-
|
230
|
-
This would compile directly into:
|
231
|
-
|
232
|
-
```javascript
|
233
|
-
(function($opal) {
|
234
|
-
var $klass = $opal.klass, self = $opal.top;
|
235
|
-
self.$puts("foo");
|
236
|
-
})(Opal);
|
237
|
-
```
|
238
|
-
|
239
|
-
Most of the helpers are no longer present as they are not used in this
|
240
|
-
example.
|
241
|
-
|
242
|
-
## Using compiled sources
|
243
|
-
|
244
|
-
If you write the generated code as above into a file `app.js` and add
|
245
|
-
that to your HTML page, then it is obvious that `"foo"` would be
|
246
|
-
written to the browser's console.
|
247
|
-
|
248
|
-
## Debugging and finding errors
|
249
|
-
|
250
|
-
Because Opal does not aim to be fully compatible with ruby, there are
|
251
|
-
some instances where things can break and it may not be entirely
|
252
|
-
obvious what went wrong.
|
253
|
-
|
254
|
-
### Using javascript debuggers
|
255
|
-
|
256
|
-
As opal just generates javascript, it is useful to use a native
|
257
|
-
debugger to work through javascript code. To use a debugger, simply
|
258
|
-
add an x-string similar to the following at the place you wish to
|
259
|
-
debug:
|
260
|
-
|
261
|
-
```ruby
|
262
|
-
# .. code
|
263
|
-
`debugger`
|
264
|
-
# .. more code
|
265
|
-
```
|
266
|
-
The x-strings just pass the debugger statement straight through to the
|
267
|
-
javascript output.
|
268
|
-
|
269
|
-
All local variables and method/block arguments also keep their ruby
|
270
|
-
names except in the rare cases when the name is reserved in javascript.
|
271
|
-
In these cases, a `$` suffix is added to the name (e.g. `try` =>
|
272
|
-
`try$`).
|
data/doc/home.md
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
# Opal
|
2
|
-
|
3
|
-
[Generated Javascript](generated_javascript.md) An overview of the compiler output
|
4
|
-
|
5
|
-
[Method Missing](method_missing.md) How Opal implements method_missing
|
6
|
-
|
7
|
-
[Using Ruby from Javascript](using_ruby_from_javascript.md) How to access ruby methods from JS
|
8
|
-
|
9
|
-
## Usage
|
10
|
-
|
11
|
-
[Static Application](static_applications.md) Just build your app and dependencies to a build.js file
|
12
|
-
|
13
|
-
[Using Sprockets](using_sprockets.md) Use rack/sprockets to auto-recompile an opal application
|
14
|
-
|
15
|
-
## Compiler
|
16
|
-
|
17
|
-
[Opal Compiler](compiler.md) An overview of how the compiler works
|
data/doc/method_missing.md
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
Opal supports `method_missing`! This is a key feature of ruby, and opal wouldn't be much use without it! This page details the implementation of `method_missing` for Opal.
|
2
|
-
|
3
|
-
## Method dispatches
|
4
|
-
|
5
|
-
Firstly, a ruby call `foo.bar 1, 2, 3` is compiled into the following javascript:
|
6
|
-
|
7
|
-
```javascript
|
8
|
-
foo.$bar(1, 2, 3)
|
9
|
-
```
|
10
|
-
|
11
|
-
This should be pretty easy to read. The `bar` method has a `$` prefix just to distinguish it from underlying javascript properties, as well as ruby ivars. Methods are compiled like this to make the generated code really readable.
|
12
|
-
|
13
|
-
## Handling method_missing
|
14
|
-
|
15
|
-
Javascript does not have an equivalent of `method_missing`, so how do we handle it? If a function is missing in javascript, then a language level exception will be raised.
|
16
|
-
|
17
|
-
To get around this, we make use of our compiler. During parsing, we collect a list of all method calls made inside a ruby file, and this gives us a list of all possible method calls. We then add stub methods to the root object prototype (an opal object, not the global javascript Object) which will proxy our method missing calls for us.
|
18
|
-
|
19
|
-
For example, assume the following ruby script:
|
20
|
-
|
21
|
-
```ruby
|
22
|
-
first 1, 2, 3
|
23
|
-
second "wow".to_sym
|
24
|
-
```
|
25
|
-
|
26
|
-
After parsing, we know we only ever call 3 methods: `[:first, :second, :to_sym]`. So, imagine we could just add these 3 methods to `BasicObject` in ruby, we would get something like this:
|
27
|
-
|
28
|
-
```ruby
|
29
|
-
class BasicObject
|
30
|
-
def first(*args, &block)
|
31
|
-
method_missing(:first, *args, &block)
|
32
|
-
end
|
33
|
-
|
34
|
-
def second(*args, &block)
|
35
|
-
method_missing(:second, *args, &block)
|
36
|
-
end
|
37
|
-
|
38
|
-
def to_sym(*args, &block)
|
39
|
-
method_missing(:to_sym, *args, &block)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
```
|
43
|
-
|
44
|
-
It is obvious from here, that unless an object defines any given method, it will always resort in a dispatch to `method_missing` from one of our defined stub methods. This is how we get `method_missing` in opal.
|
45
|
-
|
46
|
-
## Optimising generated code
|
47
|
-
|
48
|
-
To optimise the generated code slightly, we reduce the code output from the compiler into the following javascript:
|
49
|
-
|
50
|
-
```javascript
|
51
|
-
Opal.add_stubs(["first", "second", "to_sym"]);
|
52
|
-
```
|
53
|
-
|
54
|
-
You will see this at the top of all your generated javascript files. This will add a stub method for all methods used in your file.
|
55
|
-
|
56
|
-
## Alternative approaches
|
57
|
-
|
58
|
-
The old approach was to inline `method_missing` calls by checking for a method on **every method dispatch**. This is still supported via a parser option, but not recommended.
|