opal 0.3.18 → 0.3.19
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -1
- data/Gemfile +1 -3
- data/README.md +472 -10
- data/Rakefile +10 -52
- data/core/array.rb +9 -14
- data/core/basic_object.rb +7 -10
- data/core/boolean.rb +5 -1
- data/core/class.rb +15 -38
- data/core/dir.rb +89 -0
- data/core/enumerable.rb +133 -57
- data/core/error.rb +15 -1
- data/core/file.rb +85 -0
- data/core/hash.rb +186 -32
- data/core/kernel.rb +30 -31
- data/core/load_order +4 -2
- data/core/module.rb +42 -62
- data/core/numeric.rb +7 -1
- data/core/object.rb +1 -1
- data/core/proc.rb +6 -2
- data/core/range.rb +16 -28
- data/core/regexp.rb +3 -3
- data/core/runtime.js +281 -350
- data/core/string.rb +100 -110
- data/docs/CNAME +1 -0
- data/docs/Rakefile +55 -0
- data/docs/css/styles.css +50 -0
- data/docs/css/syntax.css +63 -0
- data/docs/layout/post.html +3 -0
- data/docs/layout/pre.html +11 -0
- data/examples/dependencies/app.rb +3 -0
- data/lib/opal.rb +2 -1
- data/lib/opal/builder.rb +36 -10
- data/lib/opal/builder_task.rb +51 -24
- data/lib/opal/grammar.rb +2509 -2439
- data/lib/opal/grammar.y +38 -5
- data/lib/opal/lexer.rb +18 -2
- data/lib/opal/parser.rb +375 -349
- data/lib/opal/scope.rb +24 -2
- data/lib/opal/version.rb +1 -1
- data/spec/builder/build_order_spec.rb +20 -0
- data/spec/builder/lib_name_for_spec.rb +24 -0
- data/spec/grammar/call_spec.rb +9 -6
- data/spec/grammar/lambda_spec.rb +64 -0
- data/spec/grammar/sclass_spec.rb +5 -3
- data/{core/spec → test}/core/array/allocate_spec.rb +0 -0
- data/{core/spec → test}/core/array/append_spec.rb +0 -0
- data/{core/spec → test}/core/array/assoc_spec.rb +0 -0
- data/{core/spec → test}/core/array/at_spec.rb +0 -0
- data/{core/spec → test}/core/array/clear_spec.rb +0 -0
- data/{core/spec → test}/core/array/clone_spec.rb +0 -0
- data/{core/spec → test}/core/array/collect_spec.rb +0 -0
- data/{core/spec → test}/core/array/compact_spec.rb +0 -0
- data/{core/spec → test}/core/array/concat_spec.rb +0 -0
- data/{core/spec → test}/core/array/constructor_spec.rb +0 -0
- data/{core/spec → test}/core/array/count_spec.rb +0 -0
- data/{core/spec → test}/core/array/delete_at_spec.rb +0 -0
- data/{core/spec → test}/core/array/delete_if_spec.rb +0 -0
- data/{core/spec → test}/core/array/delete_spec.rb +0 -0
- data/{core/spec → test}/core/array/each_index_spec.rb +0 -0
- data/{core/spec → test}/core/array/each_spec.rb +0 -0
- data/{core/spec → test}/core/array/element_reference_spec.rb +0 -0
- data/{core/spec → test}/core/array/empty_spec.rb +0 -0
- data/{core/spec → test}/core/array/eql_spec.rb +0 -0
- data/{core/spec → test}/core/array/fetch_spec.rb +0 -0
- data/{core/spec → test}/core/array/first_spec.rb +0 -0
- data/{core/spec → test}/core/array/flatten_spec.rb +0 -0
- data/{core/spec → test}/core/array/include_spec.rb +0 -0
- data/{core/spec → test}/core/array/insert_spec.rb +0 -0
- data/{core/spec → test}/core/array/last_spec.rb +0 -0
- data/{core/spec → test}/core/array/length_spec.rb +0 -0
- data/{core/spec → test}/core/array/map_spec.rb +0 -0
- data/{core/spec → test}/core/array/plus_spec.rb +0 -0
- data/{core/spec → test}/core/array/pop_spec.rb +0 -0
- data/{core/spec → test}/core/array/push_spec.rb +0 -0
- data/{core/spec → test}/core/array/rassoc_spec.rb +0 -0
- data/{core/spec → test}/core/array/reject_spec.rb +0 -0
- data/{core/spec → test}/core/array/replace_spec.rb +0 -0
- data/{core/spec → test}/core/array/reverse_each_spec.rb +0 -0
- data/{core/spec → test}/core/array/reverse_spec.rb +0 -0
- data/{core/spec → test}/core/array/size_spec.rb +0 -0
- data/{core/spec → test}/core/array/to_ary_spec.rb +0 -0
- data/{core/spec → test}/core/array/uniq_spec.rb +0 -0
- data/{core/spec → test}/core/array/zip_spec.rb +0 -0
- data/test/core/class/fixtures/classes.rb +9 -0
- data/test/core/class/new_spec.rb +108 -0
- data/{core/spec → test}/core/enumerable/all_spec.rb +0 -0
- data/{core/spec → test}/core/enumerable/any_spec.rb +0 -0
- data/{core/spec → test}/core/enumerable/collect_spec.rb +0 -0
- data/{core/spec → test}/core/enumerable/count_spec.rb +0 -0
- data/test/core/enumerable/detect_spec.rb +48 -0
- data/test/core/enumerable/drop_spec.rb +17 -0
- data/test/core/enumerable/drop_while_spec.rb +24 -0
- data/test/core/enumerable/each_with_index_spec.rb +11 -0
- data/test/core/enumerable/each_with_object_spec.rb +17 -0
- data/test/core/enumerable/entries_spec.rb +6 -0
- data/test/core/enumerable/find_all_spec.rb +13 -0
- data/test/core/enumerable/find_index_spec.rb +45 -0
- data/test/core/enumerable/find_spec.rb +48 -0
- data/test/core/enumerable/first_spec.rb +40 -0
- data/{core/spec → test}/core/enumerable/fixtures/classes.rb +19 -0
- data/test/core/enumerable/grep_spec.rb +21 -0
- data/test/core/enumerable/take_spec.rb +40 -0
- data/test/core/enumerable/to_a_spec.rb +6 -0
- data/{core/spec → test}/core/false/and_spec.rb +0 -0
- data/{core/spec → test}/core/false/inspect_spec.rb +0 -0
- data/{core/spec → test}/core/false/or_spec.rb +0 -0
- data/{core/spec → test}/core/false/to_s_spec.rb +0 -0
- data/{core/spec → test}/core/false/xor_spec.rb +0 -0
- data/test/core/file/expand_path_spec.rb +20 -0
- data/{core/spec → test}/core/hash/allocate_spec.rb +0 -0
- data/{core/spec → test}/core/hash/assoc_spec.rb +0 -0
- data/{core/spec → test}/core/hash/clear_spec.rb +0 -0
- data/{core/spec → test}/core/hash/clone_spec.rb +0 -0
- data/test/core/hash/default_spec.rb +9 -0
- data/{core/spec → test}/core/hash/delete_if_spec.rb +0 -0
- data/test/core/hash/each_key_spec.rb +15 -0
- data/test/core/hash/each_pair_spec.rb +30 -0
- data/test/core/hash/each_spec.rb +30 -0
- data/test/core/hash/each_value_spec.rb +15 -0
- data/{core/spec → test}/core/hash/element_reference_spec.rb +14 -0
- data/{core/spec → test}/core/hash/element_set_spec.rb +1 -0
- data/test/core/hash/empty_spec.rb +10 -0
- data/test/core/hash/fetch_spec.rb +24 -0
- data/test/core/hash/flatten_spec.rb +46 -0
- data/test/core/hash/has_key_spec.rb +24 -0
- data/test/core/hash/has_value_spec.rb +12 -0
- data/test/core/hash/include_spec.rb +24 -0
- data/test/core/hash/index_spec.rb +13 -0
- data/test/core/hash/indexes_spec.rb +9 -0
- data/test/core/hash/indices_spec.rb +9 -0
- data/test/core/hash/invert_spec.rb +12 -0
- data/test/core/hash/keep_if_spec.rb +18 -0
- data/test/core/hash/key_spec.rb +24 -0
- data/test/core/hash/keys_spec.rb +10 -0
- data/test/core/hash/length_spec.rb +10 -0
- data/test/core/hash/member_spec.rb +24 -0
- data/{core/spec → test}/core/hash/merge_spec.rb +0 -0
- data/{core/spec → test}/core/hash/new_spec.rb +0 -0
- data/test/core/hash/rassoc_spec.rb +34 -0
- data/test/core/hash/replace_spec.rb +7 -0
- data/test/core/hash/select_spec.rb +52 -0
- data/test/core/hash/shift_spec.rb +19 -0
- data/test/core/hash/size_spec.rb +10 -0
- data/test/core/hash/update_spec.rb +17 -0
- data/test/core/hash/value_spec.rb +12 -0
- data/test/core/hash/values_at_spec.rb +9 -0
- data/test/core/hash/values_spec.rb +7 -0
- data/test/core/kernel/eql_spec.rb +15 -0
- data/test/core/kernel/equal_value_spec.rb +12 -0
- data/test/core/kernel/loop_spec.rb +23 -0
- data/test/core/kernel/nil_spec.rb +7 -0
- data/test/core/kernel/proc_spec.rb +9 -0
- data/test/core/kernel/rand_spec.rb +14 -0
- data/test/core/kernel/respond_to_spec.rb +24 -0
- data/test/core/kernel/send_spec.rb +56 -0
- data/test/core/kernel/tap_spec.rb +10 -0
- data/test/core/kernel/to_s_spec.rb +5 -0
- data/{core/spec → test}/core/matchdata/to_a_spec.rb +0 -0
- data/{core/spec → test}/core/nil/and_spec.rb +0 -0
- data/{core/spec → test}/core/nil/inspect_spec.rb +0 -0
- data/{core/spec → test}/core/nil/nil_spec.rb +0 -0
- data/{core/spec → test}/core/nil/or_spec.rb +0 -0
- data/{core/spec → test}/core/nil/to_a_spec.rb +0 -0
- data/{core/spec → test}/core/nil/to_f_spec.rb +0 -0
- data/{core/spec → test}/core/nil/to_i_spec.rb +0 -0
- data/{core/spec → test}/core/nil/to_s_spec.rb +0 -0
- data/{core/spec → test}/core/nil/xor_spec.rb +0 -0
- data/{core/spec → test}/core/numeric/equal_value_spec.rb +0 -0
- data/test/core/range/begin_spec.rb +9 -0
- data/test/core/range/case_compare_spec.rb +16 -0
- data/test/core/range/end_spec.rb +9 -0
- data/{core/spec → test}/core/regexp/match_spec.rb +0 -0
- data/test/core/string/capitalize_spec.rb +10 -0
- data/test/core/string/casecmp_spec.rb +16 -0
- data/test/core/string/chomp_spec.rb +43 -0
- data/test/core/string/chop_spec.rb +10 -0
- data/test/core/string/chr_spec.rb +13 -0
- data/test/core/string/comparison_spec.rb +13 -0
- data/test/core/string/downcase_spec.rb +6 -0
- data/test/core/string/element_reference_spec.rb +72 -0
- data/test/core/string/empty_spec.rb +8 -0
- data/test/core/string/end_with_spec.rb +12 -0
- data/test/core/string/fixtures/classes.rb +3 -0
- data/test/core/string/gsub_spec.rb +17 -0
- data/test/core/string/include_spec.rb +12 -0
- data/test/core/string/intern_spec.rb +9 -0
- data/test/core/string/length_spec.rb +9 -0
- data/test/core/string/lstrip_spec.rb +7 -0
- data/test/core/string/match_spec.rb +27 -0
- data/test/core/string/next_spec.rb +10 -0
- data/test/core/string/ord_spec.rb +9 -0
- data/test/core/string/partition_spec.rb +10 -0
- data/test/core/string/reverse_spec.rb +7 -0
- data/test/core/string/rstrip_spec.rb +7 -0
- data/test/core/string/size_spec.rb +9 -0
- data/test/core/string/slice_spec.rb +72 -0
- data/test/core/string/split_spec.rb +5 -0
- data/test/core/string/start_with_spec.rb +12 -0
- data/test/core/string/strip_spec.rb +6 -0
- data/test/core/string/sub_spec.rb +22 -0
- data/test/core/string/succ_spec.rb +10 -0
- data/test/core/string/sum_spec.rb +5 -0
- data/test/core/string/swapcase_spec.rb +18 -0
- data/test/core/string/to_a_spec.rb +9 -0
- data/test/core/string/to_f_spec.rb +14 -0
- data/test/core/string/to_i_spec.rb +25 -0
- data/test/core/string/to_s_spec.rb +13 -0
- data/test/core/string/to_str_spec.rb +13 -0
- data/test/core/string/to_sym_spec.rb +9 -0
- data/test/core/string/upcase_spec.rb +6 -0
- data/test/core/symbol/to_proc_spec.rb +12 -0
- data/{core/spec → test}/core/true/and_spec.rb +0 -0
- data/{core/spec → test}/core/true/inspect_spec.rb +0 -0
- data/{core/spec → test}/core/true/or_spec.rb +0 -0
- data/{core/spec → test}/core/true/to_s_spec.rb +0 -0
- data/{core/spec → test}/core/true/xor_spec.rb +0 -0
- data/test/index.html +11 -0
- data/{core/spec → test}/language/alias_spec.rb +4 -0
- data/{core/spec → test}/language/and_spec.rb +0 -0
- data/{core/spec → test}/language/array_spec.rb +0 -0
- data/{core/spec → test}/language/block_spec.rb +0 -0
- data/{core/spec → test}/language/break_spec.rb +0 -0
- data/{core/spec → test}/language/case_spec.rb +0 -0
- data/{core/spec → test}/language/defined_spec.rb +0 -0
- data/{core/spec → test}/language/ensure_spec.rb +0 -0
- data/test/language/fixtures/yield.rb +23 -0
- data/{core/spec → test}/language/hash_spec.rb +0 -0
- data/{core/spec → test}/language/if_spec.rb +0 -0
- data/test/language/literal_lambda_spec.rb +47 -0
- data/{core/spec → test}/language/loop_spec.rb +0 -0
- data/{core/spec → test}/language/metaclass_spec.rb +0 -0
- data/{core/spec → test}/language/next_spec.rb +0 -0
- data/{core/spec → test}/language/or_spec.rb +0 -0
- data/{core/spec → test}/language/predefined_spec.rb +0 -0
- data/{core/spec → test}/language/regexp_spec.rb +0 -0
- data/{core/spec → test}/language/send_spec.rb +0 -0
- data/{core/spec → test}/language/singleton_class_spec.rb +0 -0
- data/{core/spec → test}/language/super_spec.rb +0 -0
- data/{core/spec → test}/language/symbol_spec.rb +0 -0
- data/{core/spec → test}/language/undef_spec.rb +0 -0
- data/{core/spec → test}/language/unless_spec.rb +0 -0
- data/{core/spec → test}/language/until_spec.rb +0 -0
- data/{core/spec → test}/language/variables_spec.rb +0 -0
- data/{core/spec → test}/language/while_spec.rb +0 -0
- data/test/language/yield_spec.rb +100 -0
- data/test/opal/array/subclassing_spec.rb +32 -0
- data/test/opal/class/bridge_class_spec.rb +37 -0
- data/test/opal/exception/subclassing_spec.rb +17 -0
- data/test/opal/runtime/_methods_spec.rb +48 -0
- data/test/opal/runtime/class_hierarchy_spec.rb +22 -0
- data/test/opal/runtime/def_spec.rb +23 -0
- data/test/opal/string/subclassing_spec.rb +26 -0
- data/test/spec_helper.rb +3 -0
- metadata +437 -111
- data/core/spec/core/class/new_spec.rb +0 -16
- data/core/spec/core/hash/default_spec.rb +0 -4
- data/core/spec/core/symbol/to_proc_spec.rb +0 -6
- data/core/spec/index.html +0 -11
- data/spec/builder/build_source_spec.rb +0 -52
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,25 +1,487 @@
|
|
1
1
|
# Opal
|
2
2
|
|
3
|
-
Opal is a ruby to javascript compiler
|
3
|
+
**Opal is a ruby to javascript compiler.** Opal aims to take ruby files
|
4
|
+
and generate efficient javascript that maintains rubys features. Opal
|
5
|
+
will, by default, generate fast and efficient code in preference to
|
6
|
+
keeping all ruby features.
|
4
7
|
|
5
|
-
|
8
|
+
Opal comes with an implementation of the ruby corelib, written in ruby,
|
9
|
+
that uses a bundled runtime (written in javascript) that tie all the
|
10
|
+
features together. Whenever possible Opal bridges to native javascript
|
11
|
+
features under the hood. The Opal gem includes the compiler used to
|
12
|
+
convert ruby sources into javascript.
|
6
13
|
|
7
|
-
|
14
|
+
Opal is [hosted on github](http://github.com/adambeynon/opal), and there
|
15
|
+
is a Freenode IRC channel at `#opal`.
|
8
16
|
|
9
|
-
##
|
17
|
+
## Downloads
|
10
18
|
|
11
|
-
|
19
|
+
The Opal runtime and corelib are distributed here, and are required to
|
20
|
+
run any code generated by opal.
|
21
|
+
|
22
|
+
[Opal version 0.3.19](http://opalrb.org/opal.js) _(14.9kb Minified And Gzipped)_
|
23
|
+
|
24
|
+
## Installation
|
25
|
+
|
26
|
+
Opal comes distributed as a gem, so either install with:
|
12
27
|
|
13
28
|
gem install opal
|
14
29
|
|
15
|
-
Or
|
30
|
+
Or add to your Gemfile:
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
gem "opal"
|
34
|
+
```
|
35
|
+
|
36
|
+
## Usage
|
37
|
+
|
38
|
+
To quickly compile ruby code into javascript, use the `Opal.parse()`
|
39
|
+
method which returns a string of javascript code:
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
require 'opal'
|
43
|
+
|
44
|
+
Opal.parse("[1, 2, 3, 4].each { |a| puts a }")
|
45
|
+
```
|
46
|
+
|
47
|
+
This will return a string of javascript similar to the following:
|
48
|
+
|
49
|
+
```javascript
|
50
|
+
(function() {
|
51
|
+
// compiled ruby
|
52
|
+
}).call(Opal.top);
|
53
|
+
```
|
54
|
+
|
55
|
+
This can then be written to a file and run in any browser.
|
56
|
+
|
57
|
+
### Creating a rake task
|
58
|
+
|
59
|
+
Using a Rakefile makes it simple to build your application code.
|
60
|
+
Assuming your code is in a file `app.rb`, add a rake task:
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
# Rakefile
|
64
|
+
|
65
|
+
require 'opal'
|
66
|
+
|
67
|
+
desc "Build opal application"
|
68
|
+
task :build do
|
69
|
+
src = File.read 'app.rb'
|
70
|
+
js = Opal.parse src
|
71
|
+
|
72
|
+
File.open('app.js', 'w+') do |out|
|
73
|
+
out.write js
|
74
|
+
end
|
75
|
+
end
|
76
|
+
```
|
77
|
+
|
78
|
+
Running `rake build` will then read your app code, compile it and then
|
79
|
+
write it out to a file ready to load in a web browser.
|
80
|
+
|
81
|
+
### Setting up html file
|
82
|
+
|
83
|
+
The generated `app.js` file can just be added into any HTML page. The
|
84
|
+
opal runtime needs to be loaded first (you can download that above).
|
85
|
+
|
86
|
+
```html
|
87
|
+
<!doctype html>
|
88
|
+
<html>
|
89
|
+
<head>
|
90
|
+
<title>Test Opal App</title>
|
91
|
+
</head>
|
92
|
+
<body>
|
93
|
+
<script src="opal.js"></script>
|
94
|
+
<script src="app.js"></script>
|
95
|
+
</body>
|
96
|
+
</html>
|
97
|
+
```
|
98
|
+
|
99
|
+
When using `Opal.parse()` as above, the generated code will be run
|
100
|
+
as soon as the page loads. Open the browsers console and you should
|
101
|
+
see the 4 numbers printed to the console.
|
102
|
+
|
103
|
+
## Builder and Dependency Builder
|
104
|
+
|
105
|
+
The previous example was useful for building very simple apps using
|
106
|
+
opal. For more complex apps with dependencies, Opal provides useful
|
107
|
+
rake tasks to get started. Assuming opal is in your lib path, create
|
108
|
+
a `Rakefile` similar to:
|
109
|
+
|
110
|
+
```ruby
|
111
|
+
# Rakefile
|
112
|
+
|
113
|
+
require 'opal'
|
114
|
+
|
115
|
+
Opal::BuilderTask.new do |t|
|
116
|
+
t.name = 'my-first-app'
|
117
|
+
t.dependencies = ['opal-json']
|
118
|
+
t.files = ['app.rb']
|
119
|
+
end
|
120
|
+
```
|
121
|
+
|
122
|
+
This simple rake task is all you need to build an app with its
|
123
|
+
dependencies.
|
124
|
+
|
125
|
+
### Building dependencies
|
126
|
+
|
127
|
+
To build the opal runtime `opal.js`, as well as `opal-json` into
|
128
|
+
`build/`, run the simple rake task:
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
rake dependencies
|
132
|
+
```
|
133
|
+
|
134
|
+
This will try and find the `opal-json` gem installed, so either
|
135
|
+
install globally with `gem install opal-json`, or add it to your
|
136
|
+
Gemfile as `gem "opal-json"` and run `bundle install`.
|
137
|
+
|
138
|
+
### Building app
|
139
|
+
|
140
|
+
To build the listed files into your application, run:
|
141
|
+
|
142
|
+
```ruby
|
143
|
+
rake build
|
144
|
+
```
|
145
|
+
|
146
|
+
This will build to `/build/my-first-app.js`. To customize the output
|
147
|
+
filename, change the `name` property in the raketask.
|
148
|
+
|
149
|
+
### Running the app
|
150
|
+
|
151
|
+
You should now be able to run the built app using a standard HTML page.
|
152
|
+
|
153
|
+
```html
|
154
|
+
<!doctype html>
|
155
|
+
<html>
|
156
|
+
<head>
|
157
|
+
<title>Test Opal App</title>
|
158
|
+
</head>
|
159
|
+
<body>
|
160
|
+
<script src="build/opal.js"></script>
|
161
|
+
<script src="build/opal-json.js"></script>
|
162
|
+
<script src="build/my-first-app.js"></script>
|
163
|
+
</body>
|
164
|
+
</html>
|
165
|
+
```
|
166
|
+
|
167
|
+
### Main file
|
168
|
+
|
169
|
+
When using the `BuilderTask`, the files generated will not be run
|
170
|
+
automatically on page load. The files are registered so they can be
|
171
|
+
loaded using `require()`. Builder is clever enough though that it will,
|
172
|
+
by default, automatically require the first file in the app to be
|
173
|
+
loaded. This will appear at the bottom of `my-first-app.js`:
|
174
|
+
|
175
|
+
```javascript
|
176
|
+
Opal.define('app', function() {
|
177
|
+
// app.rb code
|
178
|
+
});
|
179
|
+
|
180
|
+
Opal.require('app');
|
181
|
+
```
|
182
|
+
|
183
|
+
## Features And Implementation
|
184
|
+
|
185
|
+
Opal is a source-to-source compiler, so there is no VM as such and the
|
186
|
+
compiled code aims to be as fast and efficient as possible, mapping
|
187
|
+
directly to underlying javascript features and objects where possible.
|
188
|
+
|
189
|
+
### Literals
|
190
|
+
|
191
|
+
**self** is always compiled to `this`. Any context inside the generated
|
192
|
+
code is usually a function body; whether it be a method body, a block,
|
193
|
+
a class/module body or the file itself.
|
194
|
+
|
195
|
+
**true** and **false** are compiled directly into their native boolean
|
196
|
+
equivalents. This makes interaction a lot easier as there is no need
|
197
|
+
to convert values to opal specific values. It does mean that there is
|
198
|
+
only a `Boolean` ruby class available, not seperate `TrueClass` and
|
199
|
+
`FalseClass` classes.
|
200
|
+
|
201
|
+
**nil** is compiled into a `nil` reference, which inside all generated
|
202
|
+
files points to a special object which is just an instance of the ruby
|
203
|
+
`NilClass` class. This object is available externally to javascript as
|
204
|
+
`Opal.nil`.
|
205
|
+
|
206
|
+
```ruby
|
207
|
+
nil # => nil
|
208
|
+
true # => true
|
209
|
+
false # => false
|
210
|
+
self # => this
|
211
|
+
```
|
212
|
+
|
213
|
+
#### Strings
|
214
|
+
|
215
|
+
Ruby strings are compiled directly into javascript strings for
|
216
|
+
performance as well as readability. This has the side effect that Opal
|
217
|
+
does not support mutable strings - i.e. all strings are immutable.
|
218
|
+
|
219
|
+
#### Symbols
|
220
|
+
|
221
|
+
For performance reasons, symbols compile directly into strings. Opal
|
222
|
+
supports all the symbol syntaxes, but does not have a real `Symbol`
|
223
|
+
class. Symbols and Strings can therefore be used interchangeably.
|
224
|
+
|
225
|
+
```ruby
|
226
|
+
"hello world!" # => "hello world!"
|
227
|
+
:foo # => "foo"
|
228
|
+
<<-EOS # => "\nHello there.\n"
|
229
|
+
Hello there.
|
230
|
+
EOS
|
231
|
+
```
|
232
|
+
|
233
|
+
#### Numbers
|
234
|
+
|
235
|
+
In Opal there is a single class for numbers; `Numeric`. To keep opal
|
236
|
+
as performant as possible, ruby numbers are mapped to native numbers.
|
237
|
+
This has the side effect that all numbers must be of the same class.
|
238
|
+
Most relevant methods from `Integer`, `Float` and `Numeric` are
|
239
|
+
implemented on this class.
|
240
|
+
|
241
|
+
```ruby
|
242
|
+
42 # => 42
|
243
|
+
3.142 # => 3.142
|
244
|
+
```
|
245
|
+
|
246
|
+
#### Arrays
|
247
|
+
|
248
|
+
Ruby arrays are compiled directly into javascript arrays. Special
|
249
|
+
ruby syntaxes for word arrays etc are also supported.
|
250
|
+
|
251
|
+
```ruby
|
252
|
+
[1, 2, 3, 4] # => [1, 2, 3, 4]
|
253
|
+
%w[foo bar baz] # => ["foo", "bar", "baz"]
|
254
|
+
```
|
16
255
|
|
17
|
-
|
256
|
+
#### Hash
|
18
257
|
|
19
|
-
|
258
|
+
Inside a generated ruby script, a function `__hash` is available which
|
259
|
+
creates a new hash. This is also available in javascript as `Opal.hash`
|
260
|
+
and simply returns a new instance of the `Hash` class.
|
20
261
|
|
21
|
-
|
262
|
+
```ruby
|
263
|
+
{ :foo => 100, :baz => 700 } # => __hash("foo", 100, "baz", 700)
|
264
|
+
{ foo: 42, bar: [1, 2, 3] } # => __hash("foo", 42, "bar", [1, 2, 3])
|
265
|
+
```
|
266
|
+
|
267
|
+
#### Range
|
268
|
+
|
269
|
+
Similar to hash, there is a function `__range` available to create
|
270
|
+
range instances.
|
271
|
+
|
272
|
+
```ruby
|
273
|
+
1..4 # => __range(1, 4, true)
|
274
|
+
3...7 # => __range(3, 7, false)
|
275
|
+
```
|
276
|
+
|
277
|
+
### Methods
|
278
|
+
|
279
|
+
A ruby method is just compiled directly into a function definition.
|
280
|
+
These functions are added to the constructor's prototype so they can
|
281
|
+
be called just like any javascript function. All ruby methods are
|
282
|
+
defined with a `$` prefix to try and isolate them from javascript
|
283
|
+
methods.
|
284
|
+
|
285
|
+
#### Method Calls
|
286
|
+
|
287
|
+
All method arguments are passed to the native function just like normal
|
288
|
+
javascript function calls. Therefore, the given ruby code:
|
289
|
+
|
290
|
+
```ruby
|
291
|
+
do_something 1, 2, 3
|
292
|
+
self.length
|
293
|
+
[1, 2, 3].push 5
|
294
|
+
```
|
295
|
+
|
296
|
+
Will be compiled into the easy to read javascript:
|
297
|
+
|
298
|
+
```javascript
|
299
|
+
this.$do_something(1, 2, 3);
|
300
|
+
this.$length();
|
301
|
+
[1, 2, 3].$push(5);
|
302
|
+
```
|
303
|
+
|
304
|
+
There are some certain characters which are valid as ruby method names
|
305
|
+
but not as javascript identifiers. These method calls are encoded to
|
306
|
+
keep the generated method names sane.
|
307
|
+
|
308
|
+
```ruby
|
309
|
+
self.loaded? # => this.$loaded$p()
|
310
|
+
self.load! # => this.$load$b()
|
311
|
+
self.loaded = true # => this.$loaded$e(true)
|
312
|
+
self << :bar # => this.$lshift$("bar")
|
313
|
+
```
|
314
|
+
|
315
|
+
Finally, method calls with splat arguments are also supported:
|
316
|
+
|
317
|
+
```ruby
|
318
|
+
self.push *[1, 2, 3]
|
319
|
+
# => this.$push.apply(this, [1, 2, 3])
|
320
|
+
```
|
321
|
+
|
322
|
+
#### Optimized Math Operators
|
323
|
+
|
324
|
+
In ruby, all math operators are method calls, but compiling this into
|
325
|
+
javascript would end up being too slow. For this reason, math
|
326
|
+
operators are optimized to test first if the receiver is a number, and
|
327
|
+
if so then to just carry out the math call.
|
328
|
+
|
329
|
+
```ruby
|
330
|
+
3 + 4
|
331
|
+
```
|
332
|
+
|
333
|
+
This ruby code will then be compiled into the following javascript:
|
334
|
+
|
335
|
+
```javascript
|
336
|
+
(a = 3, b = 4, typeof(a) === "number" ? a + b : a.$plus(b))
|
337
|
+
```
|
338
|
+
|
339
|
+
This ternary statement falls back on sending a method to the receiver
|
340
|
+
so all non-numeric receivers will still have the normal method call
|
341
|
+
being sent. This optimization makes math operators a **lot faster**.
|
342
|
+
Currently, the optimized method calls are `+`, `-`, `*` and `/`.
|
343
|
+
|
344
|
+
#### Method Definitions
|
345
|
+
|
346
|
+
Methods are implemented as regular javascript functions. Assuming the
|
347
|
+
following method is defined inside a class body:
|
348
|
+
|
349
|
+
```ruby
|
350
|
+
def to_s
|
351
|
+
inspect
|
352
|
+
end
|
353
|
+
```
|
354
|
+
|
355
|
+
This would generate the following javascript. (`def.` is a local
|
356
|
+
variable set to be the class's instance prototype. It is used
|
357
|
+
for minimization of code as well as trying to be readable).
|
358
|
+
|
359
|
+
```javascript
|
360
|
+
def.$to_s = function() {
|
361
|
+
return this.$inspect();
|
362
|
+
};
|
363
|
+
```
|
364
|
+
|
365
|
+
The defined name retains the `$` prefix outlined above, and the `self`
|
366
|
+
value for the method is `this`, which will be the receiver.
|
367
|
+
|
368
|
+
Normal arguments, splat args and optional args are all supported:
|
369
|
+
|
370
|
+
```ruby
|
371
|
+
def norm(a, b, c)
|
372
|
+
|
373
|
+
end
|
374
|
+
|
375
|
+
def opt(a, b = 100)
|
376
|
+
|
377
|
+
end
|
378
|
+
|
379
|
+
def rest(a, *b)
|
380
|
+
|
381
|
+
end
|
382
|
+
```
|
383
|
+
|
384
|
+
The generated code reads as expected:
|
385
|
+
|
386
|
+
```javascript
|
387
|
+
def.$norm = function(a, b, c) {
|
388
|
+
return nil;
|
389
|
+
};
|
390
|
+
|
391
|
+
def.$opt = function(a, b) {
|
392
|
+
if (b == null) b = 100;
|
393
|
+
return nil;
|
394
|
+
};
|
395
|
+
|
396
|
+
def.$rest = function(a, b) {
|
397
|
+
b = __slice.call(arguments, 1);
|
398
|
+
return nil;
|
399
|
+
};
|
400
|
+
```
|
401
|
+
|
402
|
+
Currently, in opal there is no argument length checking to ensure that
|
403
|
+
the correct number of arguments get passed to a function. This can be
|
404
|
+
enabled in debug mode, but is not included in production builds as it
|
405
|
+
adds a lot of overhead to **every** method call.
|
406
|
+
|
407
|
+
### Compiled Files
|
408
|
+
|
409
|
+
As described above, a compiled ruby source gets generated into a string
|
410
|
+
of javascript code that is wrapped inside an anonymous function. This
|
411
|
+
looks similar to the following:
|
412
|
+
|
413
|
+
```javascript
|
414
|
+
(function(undefined) {
|
415
|
+
var nil = Opal.nil, __slice = Opal.slice, __klass = Opal.klass;
|
416
|
+
// generated code
|
417
|
+
}).call(Opal.top);
|
418
|
+
```
|
419
|
+
|
420
|
+
This function gets called with `Opal.top` as the context, which is the
|
421
|
+
top level object available to ruby (`main`). Inside the function, `nil`
|
422
|
+
is assigned to ensure a local copy is available, as well as all the
|
423
|
+
helper methods used within the generated file. There is no return value
|
424
|
+
from these functions as they are not used anywhere.
|
425
|
+
|
426
|
+
As a complete example, assuming the following code:
|
427
|
+
|
428
|
+
```ruby
|
429
|
+
puts "foo"
|
430
|
+
```
|
431
|
+
|
432
|
+
This would compile directly into:
|
433
|
+
|
434
|
+
```javascript
|
435
|
+
(function(undefined) {
|
436
|
+
var nil = Opal.nil;
|
437
|
+
this.$puts("foo");
|
438
|
+
}).call(Opal.top);
|
439
|
+
```
|
440
|
+
|
441
|
+
Most of the helpers are no longer present as they are not used in this
|
442
|
+
example.
|
443
|
+
|
444
|
+
### Using compiled sources
|
445
|
+
|
446
|
+
If you write the generated code as above into a file `app.js` and add
|
447
|
+
that to your HTML page, then it is obvious that `"foo"` would be
|
448
|
+
written to the browser's console.
|
22
449
|
|
23
450
|
## License
|
24
451
|
|
25
|
-
Opal is released under the MIT license.
|
452
|
+
Opal is released under the MIT license.
|
453
|
+
|
454
|
+
## Change Log
|
455
|
+
|
456
|
+
**0.3.19** _(30 May 2012)_
|
457
|
+
|
458
|
+
* Add BasicObject as the root class
|
459
|
+
* Add `Opal.define` and `Opal.require` for requiring files
|
460
|
+
* Builder uses a `main` option to dictate which file to require on load
|
461
|
+
* Completely revamp runtime to reduce helper methods
|
462
|
+
* Allow native bridges (Array, String, etc) to be subclassed
|
463
|
+
* Make sure `.js` files can be built with `Opal::Builder`
|
464
|
+
* Include the current file name when raising parse errors
|
465
|
+
|
466
|
+
**0.3.18** _(20 May 2012)_
|
467
|
+
|
468
|
+
* Fix various core lib bugs
|
469
|
+
* Completely remove `require` from corelib
|
470
|
+
* Improve Builder to detect dependencies in files
|
471
|
+
|
472
|
+
**0.3.17** _(19 May 2012)_
|
473
|
+
|
474
|
+
* Revamp of Builder and Parser tools
|
475
|
+
* Remove opal-repl
|
476
|
+
* Added a lot of specs for core lib
|
477
|
+
|
478
|
+
**0.3.16** _(15 January 2012)_
|
479
|
+
|
480
|
+
* Added HEREDOCS support in parser
|
481
|
+
* Parser now handles masgn (mass/multi assignments)
|
482
|
+
* More useful DependencyBuilder class to build gems dependencies
|
483
|
+
* Blocks no longer passed as an argument in method calls
|
484
|
+
|
485
|
+
**0.3.15**
|
486
|
+
|
487
|
+
* Initial Release.
|