opal 0.9.0.beta2 → 0.9.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.jshintrc +2 -1
- data/.travis.yml +8 -4
- data/CHANGELOG.md +270 -251
- data/CONTRIBUTING.md +41 -0
- data/README.md +8 -8
- data/Rakefile +1 -1
- data/lib/opal/cli.rb +1 -0
- data/lib/opal/cli_options.rb +2 -2
- data/lib/opal/cli_runners.rb +1 -0
- data/lib/opal/cli_runners/nashorn.rb +58 -0
- data/lib/opal/cli_runners/phantom.js +11 -9
- data/lib/opal/compiler.rb +2 -0
- data/lib/opal/erb.rb +2 -1
- data/lib/opal/nodes/def.rb +15 -6
- data/lib/opal/nodes/helpers.rb +1 -1
- data/lib/opal/nodes/literal.rb +1 -1
- data/lib/opal/nodes/masgn.rb +79 -29
- data/lib/opal/nodes/module.rb +1 -1
- data/lib/opal/nodes/top.rb +6 -2
- data/lib/opal/parser.rb +1 -0
- data/lib/opal/parser/grammar.rb +3160 -3083
- data/lib/opal/parser/grammar.y +39 -11
- data/lib/opal/parser/lexer.rb +15 -13
- data/lib/opal/parser/sexp.rb +5 -0
- data/lib/opal/version.rb +1 -1
- data/opal/corelib/array.rb +21 -6
- data/opal/corelib/basic_object.rb +17 -4
- data/opal/corelib/class.rb +1 -1
- data/opal/corelib/constants.rb +2 -2
- data/opal/corelib/enumerator.rb +2 -0
- data/opal/corelib/hash.rb +50 -50
- data/opal/corelib/helpers.rb +1 -1
- data/opal/corelib/io.rb +9 -6
- data/opal/corelib/kernel.rb +37 -9
- data/opal/corelib/module.rb +6 -17
- data/opal/corelib/nil.rb +4 -0
- data/opal/corelib/number.rb +0 -4
- data/opal/corelib/runtime.js +637 -662
- data/opal/corelib/struct.rb +7 -3
- data/spec/filters/bugs/array.rb +4 -9
- data/spec/filters/bugs/basicobject.rb +1 -15
- data/spec/filters/bugs/date.rb +4 -26
- data/spec/filters/bugs/enumerable.rb +26 -1
- data/spec/filters/bugs/enumerator.rb +4 -4
- data/spec/filters/bugs/exception.rb +1 -7
- data/spec/filters/bugs/float.rb +14 -0
- data/spec/filters/bugs/hash.rb +0 -2
- data/spec/filters/bugs/integer.rb +1 -1
- data/spec/filters/bugs/kernel.rb +47 -66
- data/spec/filters/bugs/language.rb +1 -2
- data/spec/filters/bugs/module.rb +11 -14
- data/spec/filters/bugs/numeric.rb +3 -3
- data/spec/filters/bugs/proc.rb +0 -1
- data/spec/filters/bugs/range.rb +2 -3
- data/spec/filters/bugs/regexp.rb +15 -17
- data/spec/filters/bugs/set.rb +2 -2
- data/spec/filters/bugs/string.rb +29 -5
- data/spec/filters/bugs/{strscan.rb → stringscanner.rb} +9 -10
- data/spec/filters/bugs/struct.rb +0 -4
- data/spec/filters/bugs/time.rb +2 -3
- data/spec/filters/bugs/unboundmethod.rb +3 -0
- data/spec/filters/unsupported/freeze.rb +2 -1
- data/spec/filters/unsupported/taint.rb +2 -0
- data/spec/lib/parser/aref_spec.rb +10 -0
- data/spec/lib/parser/lambda_spec.rb +14 -0
- data/spec/lib/parser/op_asgn_spec.rb +17 -0
- data/spec/lib/parser/return_spec.rb +5 -0
- data/spec/lib/parser/unary_spec.rb +4 -0
- data/spec/lib/sprockets/erb_spec.rb +1 -1
- data/spec/mspec/opal/formatters.rb +159 -0
- data/{lib → spec}/mspec/opal/runner.rb +0 -160
- data/spec/opal/core/hash/internals_spec.rb +162 -162
- data/spec/opal/core/kernel/at_exit_spec.rb +70 -0
- data/spec/opal/core/kernel/extend_spec.rb +1 -1
- data/spec/opal/core/kernel/instance_variables_spec.rb +56 -0
- data/spec/opal/core/language/equal_spec.rb +8 -0
- data/spec/opal/core/language/predefined_spec.rb +1 -1
- data/spec/opal/core/language/ternary_operator_spec.rb +14 -0
- data/spec/opal/core/language/versions/{hash_1.9.rb → hash_1_9_spec.rb} +5 -0
- data/spec/opal/core/module/fixtures/classes.rb +11 -1
- data/spec/opal/core/module/method_lookup_spec.rb +13 -0
- data/spec/opal/core/runtime/super_spec.rb +10 -0
- data/spec/opal/stdlib/native/new_spec.rb +84 -0
- data/spec/opal/stdlib/strscan/scan_spec.rb +11 -0
- data/spec/rubyspecs +6 -9
- data/spec/spec_helper.rb +9 -21
- data/stdlib/date.rb +121 -1
- data/stdlib/js.rb +13 -5
- data/stdlib/json.rb +3 -3
- data/stdlib/nashorn.rb +5 -0
- data/stdlib/nashorn/file.rb +13 -0
- data/stdlib/nashorn/io.rb +2 -0
- data/stdlib/native.rb +12 -4
- data/stdlib/nodejs/io.rb +5 -2
- data/stdlib/opal/platform.rb +19 -0
- data/stdlib/phantomjs.rb +4 -0
- data/stdlib/strscan.rb +1 -1
- data/tasks/building.rake +2 -1
- data/tasks/testing.rake +29 -34
- data/tasks/testing/{phantomjs1-sprockets.js → sprockets-phantomjs.js} +2 -20
- data/vendored-minitest/minitest/test.rb +7 -15
- metadata +32 -9
- data/lib/mspec/opal/main.rb.erb +0 -9
data/opal/corelib/helpers.rb
CHANGED
data/opal/corelib/io.rb
CHANGED
@@ -18,7 +18,11 @@ class IO
|
|
18
18
|
string.size
|
19
19
|
end
|
20
20
|
|
21
|
-
attr_accessor :sync
|
21
|
+
attr_accessor :sync, :tty
|
22
|
+
|
23
|
+
def flush
|
24
|
+
# noop
|
25
|
+
end
|
22
26
|
|
23
27
|
module Writable
|
24
28
|
def <<(string)
|
@@ -65,9 +69,8 @@ STDERR = $stderr = IO.new
|
|
65
69
|
STDIN = $stdin = IO.new
|
66
70
|
STDOUT = $stdout = IO.new
|
67
71
|
|
72
|
+
STDOUT.write_proc = `typeof(process) === 'object' ? function(s){process.stdout.write(s)} : function(s){console.log(s)}`
|
73
|
+
STDERR.write_proc = `typeof(process) === 'object' ? function(s){process.stderr.write(s)} : function(s){console.warn(s)}`
|
68
74
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
$stdout.extend(IO::Writable)
|
73
|
-
$stderr.extend(IO::Writable)
|
75
|
+
STDOUT.extend(IO::Writable)
|
76
|
+
STDERR.extend(IO::Writable)
|
data/opal/corelib/kernel.rb
CHANGED
@@ -105,7 +105,7 @@ module Kernel
|
|
105
105
|
def copy_instance_variables(other)
|
106
106
|
%x{
|
107
107
|
for (var name in other) {
|
108
|
-
if (name.charAt(0) !== '$') {
|
108
|
+
if (other.hasOwnProperty(name) && name.charAt(0) !== '$') {
|
109
109
|
self[name] = other[name];
|
110
110
|
}
|
111
111
|
}
|
@@ -177,7 +177,12 @@ module Kernel
|
|
177
177
|
end
|
178
178
|
|
179
179
|
def exit(status = true)
|
180
|
-
$__at_exit__
|
180
|
+
$__at_exit__ ||= []
|
181
|
+
loop do
|
182
|
+
block = $__at_exit__.pop
|
183
|
+
block ? block.call : break
|
184
|
+
end
|
185
|
+
|
181
186
|
status = 0 if `status === true` # it's in JS because it can be null/undef
|
182
187
|
`Opal.exit(status);`
|
183
188
|
nil
|
@@ -190,6 +195,10 @@ module Kernel
|
|
190
195
|
for (var i = mods.length - 1; i >= 0; i--) {
|
191
196
|
var mod = mods[i];
|
192
197
|
|
198
|
+
if (!mod.$$is_module) {
|
199
|
+
#{raise TypeError, "wrong argument type #{`mod`.class} (expected Module)"};
|
200
|
+
}
|
201
|
+
|
193
202
|
#{`mod`.append_features `singleton`};
|
194
203
|
#{`mod`.extended self};
|
195
204
|
}
|
@@ -740,7 +749,7 @@ module Kernel
|
|
740
749
|
end
|
741
750
|
|
742
751
|
def hash
|
743
|
-
|
752
|
+
__id__
|
744
753
|
end
|
745
754
|
|
746
755
|
def initialize_copy(other)
|
@@ -770,7 +779,7 @@ module Kernel
|
|
770
779
|
name = Opal.instance_variable_name!(name)
|
771
780
|
|
772
781
|
%x{
|
773
|
-
var ivar = self[name.substr(1)];
|
782
|
+
var ivar = self[Opal.ivar(name.substr(1))];
|
774
783
|
|
775
784
|
return ivar == null ? nil : ivar;
|
776
785
|
}
|
@@ -779,18 +788,37 @@ module Kernel
|
|
779
788
|
def instance_variable_set(name, value)
|
780
789
|
name = Opal.instance_variable_name!(name)
|
781
790
|
|
782
|
-
`self[name.substr(1)] = value`
|
791
|
+
`self[Opal.ivar(name.substr(1))] = value`
|
792
|
+
end
|
793
|
+
|
794
|
+
def remove_instance_variable(name)
|
795
|
+
name = Opal.instance_variable_name!(name)
|
796
|
+
|
797
|
+
%x{
|
798
|
+
var key = Opal.ivar(name.substr(1)),
|
799
|
+
val;
|
800
|
+
if (self.hasOwnProperty(key)) {
|
801
|
+
val = self[key];
|
802
|
+
delete self[key];
|
803
|
+
return val;
|
804
|
+
}
|
805
|
+
}
|
806
|
+
|
807
|
+
raise NameError, "instance variable #{name} not defined"
|
783
808
|
end
|
784
809
|
|
785
810
|
def instance_variables
|
786
811
|
%x{
|
787
|
-
var result = [];
|
812
|
+
var result = [], ivar;
|
788
813
|
|
789
814
|
for (var name in self) {
|
790
|
-
if (name.charAt(0) !== '$') {
|
791
|
-
if (name
|
792
|
-
|
815
|
+
if (self.hasOwnProperty(name) && name.charAt(0) !== '$') {
|
816
|
+
if (name.substr(-1) === '$') {
|
817
|
+
ivar = name.slice(0, name.length - 1);
|
818
|
+
} else {
|
819
|
+
ivar = name;
|
793
820
|
}
|
821
|
+
result.push('@' + ivar);
|
794
822
|
}
|
795
823
|
}
|
796
824
|
|
data/opal/corelib/module.rb
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
class Module
|
2
2
|
def self.new(&block)
|
3
3
|
%x{
|
4
|
-
|
5
|
-
var klass = Opal.boot(Opal.Module, AnonModule);
|
4
|
+
var klass = Opal.boot_module_object();
|
6
5
|
klass.$$name = nil;
|
7
6
|
klass.$$class = Opal.Module;
|
8
7
|
klass.$$dep = []
|
@@ -67,21 +66,7 @@ class Module
|
|
67
66
|
end
|
68
67
|
|
69
68
|
def ancestors
|
70
|
-
|
71
|
-
var parent = self,
|
72
|
-
result = [];
|
73
|
-
|
74
|
-
while (parent) {
|
75
|
-
result.push(parent);
|
76
|
-
for (var i=0; i < parent.$$inc.length; i++) {
|
77
|
-
result = result.concat(parent.$$inc[i].$ancestors());
|
78
|
-
}
|
79
|
-
|
80
|
-
parent = parent.$$is_class ? parent.$$super : null;
|
81
|
-
}
|
82
|
-
|
83
|
-
return result;
|
84
|
-
}
|
69
|
+
`Opal.ancestors(self)`
|
85
70
|
end
|
86
71
|
|
87
72
|
def append_features(klass)
|
@@ -347,6 +332,10 @@ class Module
|
|
347
332
|
continue;
|
348
333
|
}
|
349
334
|
|
335
|
+
if (!mod.$$is_module) {
|
336
|
+
#{raise TypeError, "wrong argument type #{`mod`.class} (expected Module)"};
|
337
|
+
}
|
338
|
+
|
350
339
|
#{`mod`.append_features self};
|
351
340
|
#{`mod`.included self};
|
352
341
|
}
|
data/opal/corelib/nil.rb
CHANGED
data/opal/corelib/number.rb
CHANGED
data/opal/corelib/runtime.js
CHANGED
@@ -4,6 +4,36 @@
|
|
4
4
|
return this.Opal;
|
5
5
|
}
|
6
6
|
|
7
|
+
var nil;
|
8
|
+
|
9
|
+
// The actual class for BasicObject
|
10
|
+
var BasicObject;
|
11
|
+
|
12
|
+
// The actual Object class.
|
13
|
+
// The leading underscore is to avoid confusion with window.Object()
|
14
|
+
var _Object;
|
15
|
+
|
16
|
+
// The actual Module class
|
17
|
+
var Module;
|
18
|
+
|
19
|
+
// The actual Class class
|
20
|
+
var Class;
|
21
|
+
|
22
|
+
// Constructor for instances of BasicObject
|
23
|
+
function BasicObject_alloc(){}
|
24
|
+
|
25
|
+
// Constructor for instances of Object
|
26
|
+
function Object_alloc(){}
|
27
|
+
|
28
|
+
// Constructor for instances of Class
|
29
|
+
function Class_alloc(){}
|
30
|
+
|
31
|
+
// Constructor for instances of Module
|
32
|
+
function Module_alloc(){}
|
33
|
+
|
34
|
+
// Constructor for instances of NilClass (nil)
|
35
|
+
function NilClass_alloc(){}
|
36
|
+
|
7
37
|
// The Opal object that is exposed globally
|
8
38
|
var Opal = this.Opal = {};
|
9
39
|
|
@@ -51,26 +81,25 @@
|
|
51
81
|
// Exit function, this should be replaced by platform specific implementation
|
52
82
|
// (See nodejs and phantom for examples)
|
53
83
|
Opal.exit = function(status) { if (Opal.gvars.DEBUG) console.log('Exited with status '+status); };
|
54
|
-
|
84
|
+
|
55
85
|
// keeps track of exceptions for $!
|
56
86
|
Opal.exceptions = [];
|
57
87
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
*/
|
88
|
+
// Get a constant on the given scope. Every class and module in Opal has a
|
89
|
+
// scope used to store, and inherit, constants. For example, the top level
|
90
|
+
// `Object` in ruby has a scope accessible as `Opal.Object.$$scope`.
|
91
|
+
//
|
92
|
+
// To get the `Array` class using this scope, you could use:
|
93
|
+
//
|
94
|
+
// Opal.Object.$$scope.get("Array")
|
95
|
+
//
|
96
|
+
// If a constant with the given name cannot be found, then a dispatch to the
|
97
|
+
// class/module's `#const_method` is called, which by default will raise an
|
98
|
+
// error.
|
99
|
+
//
|
100
|
+
// @param [String] name the name of the constant to lookup
|
101
|
+
// @return [RubyObject]
|
102
|
+
//
|
74
103
|
Opal.get = function(name) {
|
75
104
|
var constant = this[name];
|
76
105
|
|
@@ -81,12 +110,11 @@
|
|
81
110
|
return constant;
|
82
111
|
};
|
83
112
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
function create_scope(base, klass, id) {
|
113
|
+
// Create a new constants scope for the given class with the given
|
114
|
+
// base. Constants are looked up through their parents, so the base
|
115
|
+
// scope will be the outer scope of the new klass.
|
116
|
+
//
|
117
|
+
Opal.create_scope = function(base, klass, id) {
|
90
118
|
var const_alloc = function() {};
|
91
119
|
var const_scope = const_alloc.prototype = new base.constructor();
|
92
120
|
|
@@ -98,45 +126,51 @@
|
|
98
126
|
const_scope.constants = [];
|
99
127
|
|
100
128
|
if (id) {
|
101
|
-
Opal.cdecl(base, id, klass)
|
129
|
+
Opal.cdecl(base, id, klass);
|
130
|
+
const_alloc.displayName = id+"_alloc";
|
102
131
|
}
|
103
132
|
}
|
104
133
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
* @param [Function] constructor function to use as constructor
|
130
|
-
* @return [Class] new or existing ruby class
|
131
|
-
*/
|
134
|
+
// A `class Foo; end` expression in ruby is compiled to call this runtime
|
135
|
+
// method which either returns an existing class of the given name, or creates
|
136
|
+
// a new class in the given `base` scope.
|
137
|
+
//
|
138
|
+
// If a constant with the given name exists, then we check to make sure that
|
139
|
+
// it is a class and also that the superclasses match. If either of these
|
140
|
+
// fail, then we raise a `TypeError`. Note, superklass may be null if one was
|
141
|
+
// not specified in the ruby code.
|
142
|
+
//
|
143
|
+
// We pass a constructor to this method of the form `function ClassName() {}`
|
144
|
+
// simply so that classes show up with nicely formatted names inside debuggers
|
145
|
+
// in the web browser (or node/sprockets).
|
146
|
+
//
|
147
|
+
// The `base` is the current `self` value where the class is being created
|
148
|
+
// from. We use this to get the scope for where the class should be created.
|
149
|
+
// If `base` is an object (not a class/module), we simple get its class and
|
150
|
+
// use that as the base instead.
|
151
|
+
//
|
152
|
+
// @param [Object] base where the class is being created
|
153
|
+
// @param [Class] superklass superclass of the new class (may be null)
|
154
|
+
// @param [String] id the name of the class to be created
|
155
|
+
// @param [Function] constructor function to use as constructor
|
156
|
+
// @return [Class] new or existing ruby class
|
157
|
+
//
|
132
158
|
Opal.klass = function(base, superklass, id, constructor) {
|
159
|
+
var klass, bridged, alloc;
|
160
|
+
|
133
161
|
// If base is an object, use its class
|
134
162
|
if (!base.$$is_class && !base.$$is_module) {
|
135
163
|
base = base.$$class;
|
136
164
|
}
|
137
165
|
|
138
|
-
|
139
|
-
|
166
|
+
// If the superclass is a function then we're bridging a native JS class
|
167
|
+
if (typeof(superklass) === 'function') {
|
168
|
+
bridged = superklass;
|
169
|
+
superklass = _Object;
|
170
|
+
}
|
171
|
+
|
172
|
+
// Try to find the class in the current scope
|
173
|
+
klass = base.$$scope[id];
|
140
174
|
|
141
175
|
// If the class exists in the scope, then we must use that
|
142
176
|
if (klass && klass.$$orig_scope === base.$$scope) {
|
@@ -153,38 +187,42 @@
|
|
153
187
|
return klass;
|
154
188
|
}
|
155
189
|
|
190
|
+
// Class doesnt exist, create a new one with given superclass...
|
191
|
+
|
156
192
|
// Not specifying a superclass means we can assume it to be Object
|
157
|
-
if (superklass
|
158
|
-
superklass =
|
193
|
+
if (superklass == null) {
|
194
|
+
superklass = _Object;
|
159
195
|
}
|
160
196
|
|
161
|
-
//
|
162
|
-
|
163
|
-
boot_class_object(ObjectClass, superklass) :
|
164
|
-
boot_class(superklass, constructor);
|
197
|
+
// If bridged the JS class will also be the alloc function
|
198
|
+
alloc = bridged || boot_class_alloc(id, constructor, superklass);
|
165
199
|
|
166
|
-
//
|
200
|
+
// Create the class object (instance of Class)
|
201
|
+
klass = boot_class_object(id, superklass, alloc);
|
202
|
+
|
203
|
+
// Name the class
|
167
204
|
klass.$$name = id;
|
205
|
+
klass.displayName = id;
|
168
206
|
|
169
|
-
//
|
207
|
+
// Mark the object as a class
|
170
208
|
klass.$$is_class = true;
|
171
209
|
|
172
|
-
//
|
173
|
-
create_scope(base.$$scope, klass, id);
|
210
|
+
// Every class gets its own constant scope, inherited from current scope
|
211
|
+
Opal.create_scope(base.$$scope, klass, id);
|
174
212
|
|
175
213
|
// Name new class directly onto current scope (Opal.Foo.Baz = klass)
|
176
214
|
base[id] = base.$$scope[id] = klass;
|
177
215
|
|
178
216
|
if (bridged) {
|
179
|
-
Opal.bridge(klass,
|
217
|
+
Opal.bridge(klass, alloc);
|
180
218
|
}
|
181
219
|
else {
|
182
220
|
// Copy all parent constants to child, unless parent is Object
|
183
|
-
if (superklass !==
|
221
|
+
if (superklass !== _Object && superklass !== BasicObject) {
|
184
222
|
donate_constants(superklass, klass);
|
185
223
|
}
|
186
224
|
|
187
|
-
//
|
225
|
+
// Call .inherited() hook with new class on the superclass
|
188
226
|
if (superklass.$inherited) {
|
189
227
|
superklass.$inherited(klass);
|
190
228
|
}
|
@@ -194,33 +232,34 @@
|
|
194
232
|
};
|
195
233
|
|
196
234
|
// Create generic class with given superclass.
|
197
|
-
function
|
235
|
+
Opal.boot_class = function(superklass, constructor) {
|
198
236
|
var alloc = boot_class_alloc(null, constructor, superklass)
|
199
237
|
|
200
|
-
return boot_class_object(superklass, alloc);
|
238
|
+
return boot_class_object(null, superklass, alloc);
|
201
239
|
}
|
202
240
|
|
203
|
-
//
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
singleton_class.prototype = superklass.constructor.prototype;
|
241
|
+
// The class object itself (as in `Class.new`)
|
242
|
+
//
|
243
|
+
// @param superklass [(Opal) Class] Another class object (as in `Class.new`)
|
244
|
+
// @param alloc [constructor] The constructor that holds the prototype
|
245
|
+
// that will be used for instances of the
|
246
|
+
// newly constructed class.
|
247
|
+
function boot_class_object(id, superklass, alloc) {
|
248
|
+
// Grab the superclass prototype and use it to build an intermediary object
|
249
|
+
// in the prototype chain.
|
250
|
+
function Superclass_alloc_proxy() {};
|
251
|
+
Superclass_alloc_proxy.prototype = superklass.constructor.prototype;
|
252
|
+
function SingletonClass_alloc() {}
|
253
|
+
SingletonClass_alloc.prototype = new Superclass_alloc_proxy();
|
217
254
|
|
218
|
-
|
219
|
-
|
255
|
+
if (id) {
|
256
|
+
SingletonClass_alloc.displayName = "SingletonClass_alloc("+id+")";
|
257
|
+
}
|
220
258
|
|
221
|
-
|
259
|
+
// The built class is the only instance of its singleton_class
|
260
|
+
var klass = new SingletonClass_alloc();
|
222
261
|
|
223
|
-
setup_module_or_class_object(klass,
|
262
|
+
setup_module_or_class_object(klass, SingletonClass_alloc, superklass, alloc.prototype);
|
224
263
|
|
225
264
|
// @property $$alloc This is the constructor of instances of the current
|
226
265
|
// class. Its prototype will be used for method lookup
|
@@ -233,22 +272,21 @@
|
|
233
272
|
return klass;
|
234
273
|
}
|
235
274
|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
*/
|
275
|
+
// Adds common/required properties to a module or class object
|
276
|
+
// (as in `Module.new` / `Class.new`)
|
277
|
+
//
|
278
|
+
// @param module The module or class that needs to be prepared
|
279
|
+
//
|
280
|
+
// @param constructor The constructor of the module or class itself,
|
281
|
+
// usually it's already assigned by using `new`. Some
|
282
|
+
// ipothesis on why it's needed can be found below.
|
283
|
+
//
|
284
|
+
// @param superklass The superclass of the class/module object, for modules
|
285
|
+
// is `Module` (of `Module` in JS context)
|
286
|
+
//
|
287
|
+
// @param prototype The prototype on which the class/module methods will
|
288
|
+
// be stored.
|
289
|
+
//
|
252
290
|
function setup_module_or_class_object(module, constructor, superklass, prototype) {
|
253
291
|
// @property $$id Each class is assigned a unique `id` that helps
|
254
292
|
// comparation and implementation of `#object_id`
|
@@ -265,15 +303,15 @@
|
|
265
303
|
// Maybe there are some browsers not abiding (IE6?)
|
266
304
|
module.constructor = constructor;
|
267
305
|
|
268
|
-
if (superklass ===
|
306
|
+
if (superklass === Module) {
|
269
307
|
// @property $$is_module Clearly mark this as a module
|
270
308
|
module.$$is_module = true;
|
271
|
-
module.$$class =
|
309
|
+
module.$$class = Module;
|
272
310
|
}
|
273
311
|
else {
|
274
312
|
// @property $$is_class Clearly mark this as a class
|
275
313
|
module.$$is_class = true;
|
276
|
-
module.$$class =
|
314
|
+
module.$$class = Class;
|
277
315
|
}
|
278
316
|
|
279
317
|
// @property $$super the superclass, doesn't get changed by module inclusions
|
@@ -288,26 +326,25 @@
|
|
288
326
|
module.$$inc = [];
|
289
327
|
}
|
290
328
|
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
*/
|
329
|
+
// Define new module (or return existing module). The given `base` is basically
|
330
|
+
// the current `self` value the `module` statement was defined in. If this is
|
331
|
+
// a ruby module or class, then it is used, otherwise if the base is a ruby
|
332
|
+
// object then that objects real ruby class is used (e.g. if the base is the
|
333
|
+
// main object, then the top level `Object` class is used as the base).
|
334
|
+
//
|
335
|
+
// If a module of the given name is already defined in the base, then that
|
336
|
+
// instance is just returned.
|
337
|
+
//
|
338
|
+
// If there is a class of the given name in the base, then an error is
|
339
|
+
// generated instead (cannot have a class and module of same name in same base).
|
340
|
+
//
|
341
|
+
// Otherwise, a new module is created in the base with the given name, and that
|
342
|
+
// new instance is returned back (to be referenced at runtime).
|
343
|
+
//
|
344
|
+
// @param [RubyModule or Class] base class or module this definition is inside
|
345
|
+
// @param [String] id the name of the new (or existing) module
|
346
|
+
// @return [RubyModule]
|
347
|
+
//
|
311
348
|
Opal.module = function(base, id) {
|
312
349
|
var module;
|
313
350
|
|
@@ -318,7 +355,7 @@
|
|
318
355
|
if ($hasOwn.call(base.$$scope, id)) {
|
319
356
|
module = base.$$scope[id];
|
320
357
|
|
321
|
-
if (!module.$$is_module && module !==
|
358
|
+
if (!module.$$is_module && module !== _Object) {
|
322
359
|
throw Opal.TypeError.$new(id + " is not a module");
|
323
360
|
}
|
324
361
|
}
|
@@ -334,7 +371,7 @@
|
|
334
371
|
// initialize dependency tracking
|
335
372
|
module.$$dep = [];
|
336
373
|
|
337
|
-
create_scope(base.$$scope, module, id);
|
374
|
+
Opal.create_scope(base.$$scope, module, id);
|
338
375
|
|
339
376
|
// Name new module directly onto current scope (Opal.Foo.Baz = module)
|
340
377
|
base[id] = base.$$scope[id] = module;
|
@@ -343,13 +380,12 @@
|
|
343
380
|
return module;
|
344
381
|
};
|
345
382
|
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
*/
|
383
|
+
// Internal function to create a new module instance. This simply sets up
|
384
|
+
// the prototype hierarchy and method tables.
|
385
|
+
//
|
350
386
|
function boot_module_object() {
|
351
387
|
var mtor = function() {};
|
352
|
-
mtor.prototype =
|
388
|
+
mtor.prototype = Module_alloc.prototype;
|
353
389
|
|
354
390
|
function module_constructor() {}
|
355
391
|
module_constructor.prototype = new mtor();
|
@@ -357,24 +393,26 @@
|
|
357
393
|
var module = new module_constructor();
|
358
394
|
var module_prototype = {};
|
359
395
|
|
360
|
-
setup_module_or_class_object(module, module_constructor,
|
396
|
+
setup_module_or_class_object(module, module_constructor, Module, module_prototype);
|
361
397
|
|
362
398
|
return module;
|
363
399
|
}
|
364
400
|
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
401
|
+
// Make `boot_module_object` available to the JS-API
|
402
|
+
Opal.boot_module_object = boot_module_object;
|
403
|
+
|
404
|
+
// Return the singleton class for the passed object.
|
405
|
+
//
|
406
|
+
// If the given object alredy has a singleton class, then it will be stored on
|
407
|
+
// the object as the `$$meta` property. If this exists, then it is simply
|
408
|
+
// returned back.
|
409
|
+
//
|
410
|
+
// Otherwise, a new singleton object for the class or object is created, set on
|
411
|
+
// the object at `$$meta` for future use, and then returned.
|
412
|
+
//
|
413
|
+
// @param [RubyObject] object the ruby object
|
414
|
+
// @return [RubyClass] the singleton class for object
|
415
|
+
//
|
378
416
|
Opal.get_singleton_class = function(object) {
|
379
417
|
if (object.$$meta) {
|
380
418
|
return object.$$meta;
|
@@ -387,15 +425,14 @@
|
|
387
425
|
return build_object_singleton_class(object);
|
388
426
|
};
|
389
427
|
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
*/
|
428
|
+
// Build the singleton class for an existing class.
|
429
|
+
//
|
430
|
+
// NOTE: Actually in MRI a class' singleton class inherits from its
|
431
|
+
// superclass' singleton class which in turn inherits from Class.
|
432
|
+
//
|
433
|
+
// @param [RubyClass] klass
|
434
|
+
// @return [RubyClass]
|
435
|
+
//
|
399
436
|
function build_class_singleton_class(klass) {
|
400
437
|
var meta = new Opal.Class.$$alloc();
|
401
438
|
|
@@ -410,18 +447,17 @@
|
|
410
447
|
return klass.$$meta = meta;
|
411
448
|
}
|
412
449
|
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
*/
|
450
|
+
// Build the singleton class for a Ruby (non class) Object.
|
451
|
+
//
|
452
|
+
// @param [RubyObject] object
|
453
|
+
// @return [RubyClass]
|
454
|
+
//
|
419
455
|
function build_object_singleton_class(object) {
|
420
456
|
var orig_class = object.$$class,
|
421
457
|
class_id = "#<Class:#<" + orig_class.$$name + ":" + orig_class.$$id + ">>";
|
422
458
|
|
423
|
-
var Singleton = function
|
424
|
-
var meta = Opal.
|
459
|
+
var Singleton = function() {};
|
460
|
+
var meta = Opal.boot_class(orig_class, Singleton);
|
425
461
|
meta.$$name = class_id;
|
426
462
|
|
427
463
|
meta.$$proto = object;
|
@@ -434,109 +470,85 @@
|
|
434
470
|
return object.$$meta = meta;
|
435
471
|
}
|
436
472
|
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
## Class `$$parent` and `iclass`
|
441
|
-
|
442
|
-
To handle `super` calls, every class has a `$$parent`. This parent is
|
443
|
-
used to resolve the next class for a super call. A normal class would
|
444
|
-
have this point to its superclass. However, if a class includes a module
|
445
|
-
then this would need to take into account the module. The module would
|
446
|
-
also have to then point its `$$parent` to the actual superclass. We
|
447
|
-
cannot modify modules like this, because it might be included in more
|
448
|
-
then one class. To fix this, we actually insert an `iclass` as the class'
|
449
|
-
`$$parent` which can then point to the superclass. The `iclass` acts as
|
450
|
-
a proxy to the actual module, so the `super` chain can then search it for
|
451
|
-
the required method.
|
452
|
-
|
453
|
-
@param [RubyModule] module the module to include
|
454
|
-
@param [RubyClass] klass the target class to include module into
|
455
|
-
@returns [null]
|
456
|
-
*/
|
457
|
-
function bridge() {
|
458
|
-
var target, donator, from, name, body, ancestors, id, methods, method, i, ancestor, bridged, length;
|
459
|
-
|
460
|
-
if (arguments.length === 4) {
|
461
|
-
target = arguments[0];
|
462
|
-
from = arguments[1];
|
463
|
-
name = arguments[2];
|
464
|
-
body = arguments[3];
|
465
|
-
ancestors = target.$$bridge.$ancestors();
|
466
|
-
|
467
|
-
// order important here, we have to check for method presence in
|
468
|
-
// ancestors from the bridged class to the last ancestor
|
469
|
-
for (i = 0, length = ancestors.length; i < length; i++) {
|
470
|
-
ancestor = ancestors[i];
|
471
|
-
|
472
|
-
if ($hasOwn.call(ancestor.$$proto, name) &&
|
473
|
-
ancestor.$$proto[name] &&
|
474
|
-
!ancestor.$$proto[name].$$donated &&
|
475
|
-
!ancestor.$$proto[name].$$stub &&
|
476
|
-
ancestor !== from) {
|
477
|
-
break;
|
478
|
-
}
|
473
|
+
// Bridges a single method.
|
474
|
+
function bridge_method(target, from, name, body) {
|
475
|
+
var ancestors, i, ancestor, length;
|
479
476
|
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
477
|
+
ancestors = target.$$bridge.$ancestors();
|
478
|
+
|
479
|
+
// order important here, we have to check for method presence in
|
480
|
+
// ancestors from the bridged class to the last ancestor
|
481
|
+
for (i = 0, length = ancestors.length; i < length; i++) {
|
482
|
+
ancestor = ancestors[i];
|
483
|
+
|
484
|
+
if ($hasOwn.call(ancestor.$$proto, name) &&
|
485
|
+
ancestor.$$proto[name] &&
|
486
|
+
!ancestor.$$proto[name].$$donated &&
|
487
|
+
!ancestor.$$proto[name].$$stub &&
|
488
|
+
ancestor !== from) {
|
489
|
+
break;
|
490
|
+
}
|
491
|
+
|
492
|
+
if (ancestor === from) {
|
493
|
+
target.prototype[name] = body
|
494
|
+
break;
|
484
495
|
}
|
485
496
|
}
|
486
|
-
else {
|
487
|
-
target = arguments[0];
|
488
|
-
donator = arguments[1];
|
489
497
|
|
490
|
-
|
491
|
-
id = donator.$__id__();
|
492
|
-
methods = donator.$instance_methods();
|
498
|
+
}
|
493
499
|
|
494
|
-
|
495
|
-
|
500
|
+
// Bridges from *donator* to a *target*.
|
501
|
+
function _bridge(target, donator) {
|
502
|
+
var id, methods, method, i, bridged;
|
496
503
|
|
497
|
-
|
498
|
-
|
504
|
+
if (typeof(target) === "function") {
|
505
|
+
id = donator.$__id__();
|
506
|
+
methods = donator.$instance_methods();
|
499
507
|
|
500
|
-
|
501
|
-
|
502
|
-
}
|
508
|
+
for (i = methods.length - 1; i >= 0; i--) {
|
509
|
+
method = '$' + methods[i];
|
503
510
|
|
504
|
-
|
511
|
+
bridge_method(target, donator, method, donator.$$proto[method]);
|
505
512
|
}
|
506
|
-
else {
|
507
|
-
bridged = bridges[target.$__id__()];
|
508
513
|
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
}
|
514
|
+
if (!bridges[id]) {
|
515
|
+
bridges[id] = [];
|
516
|
+
}
|
513
517
|
|
514
|
-
|
518
|
+
bridges[id].push(target);
|
519
|
+
}
|
520
|
+
else {
|
521
|
+
bridged = bridges[target.$__id__()];
|
522
|
+
|
523
|
+
if (bridged) {
|
524
|
+
for (i = bridged.length - 1; i >= 0; i--) {
|
525
|
+
_bridge(bridged[i], donator);
|
515
526
|
}
|
527
|
+
|
528
|
+
bridges[donator.$__id__()] = bridged.slice();
|
516
529
|
}
|
517
530
|
}
|
518
531
|
}
|
519
532
|
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
*/
|
533
|
+
// The actual inclusion of a module into a class.
|
534
|
+
//
|
535
|
+
// ## Class `$$parent` and `iclass`
|
536
|
+
//
|
537
|
+
// To handle `super` calls, every class has a `$$parent`. This parent is
|
538
|
+
// used to resolve the next class for a super call. A normal class would
|
539
|
+
// have this point to its superclass. However, if a class includes a module
|
540
|
+
// then this would need to take into account the module. The module would
|
541
|
+
// also have to then point its `$$parent` to the actual superclass. We
|
542
|
+
// cannot modify modules like this, because it might be included in more
|
543
|
+
// then one class. To fix this, we actually insert an `iclass` as the class'
|
544
|
+
// `$$parent` which can then point to the superclass. The `iclass` acts as
|
545
|
+
// a proxy to the actual module, so the `super` chain can then search it for
|
546
|
+
// the required method.
|
547
|
+
//
|
548
|
+
// @param [RubyModule] module the module to include
|
549
|
+
// @param [RubyClass] klass the target class to include module into
|
550
|
+
// @return [null]
|
551
|
+
//
|
540
552
|
Opal.append_features = function(module, klass) {
|
541
553
|
var iclass, donator, prototype, methods, id, i;
|
542
554
|
|
@@ -549,7 +561,7 @@
|
|
549
561
|
|
550
562
|
klass.$$inc.push(module);
|
551
563
|
module.$$dep.push(klass);
|
552
|
-
|
564
|
+
_bridge(klass, module);
|
553
565
|
|
554
566
|
// iclass
|
555
567
|
iclass = {
|
@@ -588,14 +600,13 @@
|
|
588
600
|
// Boot a base class (makes instances).
|
589
601
|
function boot_class_alloc(id, constructor, superklass) {
|
590
602
|
if (superklass) {
|
591
|
-
var
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
ctor.displayName = id;
|
596
|
-
}
|
603
|
+
var alloc_proxy = function() {};
|
604
|
+
alloc_proxy.prototype = superklass.$$proto || superklass.prototype;
|
605
|
+
constructor.prototype = new alloc_proxy();
|
606
|
+
}
|
597
607
|
|
598
|
-
|
608
|
+
if (id) {
|
609
|
+
constructor.displayName = id+'_alloc';
|
599
610
|
}
|
600
611
|
|
601
612
|
constructor.prototype.constructor = constructor;
|
@@ -603,15 +614,14 @@
|
|
603
614
|
return constructor;
|
604
615
|
}
|
605
616
|
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
*/
|
617
|
+
// Builds the class object for core classes:
|
618
|
+
// - make the class object have a singleton class
|
619
|
+
// - make the singleton class inherit from its parent singleton class
|
620
|
+
//
|
621
|
+
// @param id [String] the name of the class
|
622
|
+
// @param alloc [Function] the constructor for the core class instances
|
623
|
+
// @param superclass [Class alloc] the constructor of the superclass
|
624
|
+
//
|
615
625
|
function boot_core_class_object(id, alloc, superclass) {
|
616
626
|
var superclass_constructor = function() {};
|
617
627
|
superclass_constructor.prototype = superclass.prototype;
|
@@ -626,8 +636,9 @@
|
|
626
636
|
|
627
637
|
setup_module_or_class_object(klass, singleton_class, superclass, alloc.prototype);
|
628
638
|
|
629
|
-
klass.$$alloc
|
630
|
-
klass.$$name
|
639
|
+
klass.$$alloc = alloc;
|
640
|
+
klass.$$name = id;
|
641
|
+
klass.displayName = id;
|
631
642
|
|
632
643
|
// Give all instances a ref to their class
|
633
644
|
alloc.prototype.$$class = klass;
|
@@ -638,24 +649,23 @@
|
|
638
649
|
return klass;
|
639
650
|
}
|
640
651
|
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
*/
|
652
|
+
// For performance, some core Ruby classes are toll-free bridged to their
|
653
|
+
// native JavaScript counterparts (e.g. a Ruby Array is a JavaScript Array).
|
654
|
+
//
|
655
|
+
// This method is used to setup a native constructor (e.g. Array), to have
|
656
|
+
// its prototype act like a normal Ruby class. Firstly, a new Ruby class is
|
657
|
+
// created using the native constructor so that its prototype is set as the
|
658
|
+
// target for th new class. Note: all bridged classes are set to inherit
|
659
|
+
// from Object.
|
660
|
+
//
|
661
|
+
// Example:
|
662
|
+
//
|
663
|
+
// Opal.bridge(self, Function);
|
664
|
+
//
|
665
|
+
// @param [Class] klass the Ruby class to bridge
|
666
|
+
// @param [Function] constructor native JavaScript constructor to use
|
667
|
+
// @return [Class] returns the passed Ruby class
|
668
|
+
//
|
659
669
|
Opal.bridge = function(klass, constructor) {
|
660
670
|
if (constructor.$$bridge) {
|
661
671
|
throw Opal.ArgumentError.$new("already bridged");
|
@@ -671,11 +681,11 @@
|
|
671
681
|
// order important here, we have to bridge from the last ancestor to the
|
672
682
|
// bridged class
|
673
683
|
for (var i = ancestors.length - 1; i >= 0; i--) {
|
674
|
-
|
684
|
+
_bridge(constructor, ancestors[i]);
|
675
685
|
}
|
676
686
|
|
677
|
-
for (var name in
|
678
|
-
var method =
|
687
|
+
for (var name in BasicObject_alloc.prototype) {
|
688
|
+
var method = BasicObject_alloc.prototype[method];
|
679
689
|
|
680
690
|
if (method && method.$$stub && !(name in constructor.prototype)) {
|
681
691
|
constructor.prototype[name] = method;
|
@@ -686,9 +696,8 @@
|
|
686
696
|
}
|
687
697
|
|
688
698
|
|
689
|
-
|
690
|
-
|
691
|
-
*/
|
699
|
+
// constant assign
|
700
|
+
//
|
692
701
|
Opal.casgn = function(base_module, name, value) {
|
693
702
|
function update(klass, name) {
|
694
703
|
klass.$$name = name;
|
@@ -705,8 +714,8 @@
|
|
705
714
|
var scope = base_module.$$scope;
|
706
715
|
|
707
716
|
if (value.$$is_class || value.$$is_module) {
|
708
|
-
// only checking
|
709
|
-
if (value.$$is_class || value.$$base_module ===
|
717
|
+
// only checking _Object prevents setting a const on an anonymous class that has a superclass that's not Object
|
718
|
+
if (value.$$is_class || value.$$base_module === _Object) {
|
710
719
|
value.$$base_module = base_module;
|
711
720
|
}
|
712
721
|
|
@@ -719,9 +728,7 @@
|
|
719
728
|
return scope[name] = value;
|
720
729
|
};
|
721
730
|
|
722
|
-
|
723
|
-
* constant decl
|
724
|
-
*/
|
731
|
+
// constant decl
|
725
732
|
Opal.cdecl = function(base_scope, name, value) {
|
726
733
|
if ((value.$$is_class || value.$$is_module) && value.$$orig_scope == null) {
|
727
734
|
value.$$name = name;
|
@@ -733,10 +740,9 @@
|
|
733
740
|
return base_scope[name] = value;
|
734
741
|
};
|
735
742
|
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
*/
|
743
|
+
// When a source module is included into the target module, we must also copy
|
744
|
+
// its constants to the target.
|
745
|
+
//
|
740
746
|
function donate_constants(source_mod, target_mod) {
|
741
747
|
var source_constants = source_mod.$$scope.constants,
|
742
748
|
target_scope = target_mod.$$scope,
|
@@ -748,9 +754,7 @@
|
|
748
754
|
}
|
749
755
|
};
|
750
756
|
|
751
|
-
|
752
|
-
* Donate methods for a module.
|
753
|
-
*/
|
757
|
+
// Donate methods for a module.
|
754
758
|
function donate(module, jsid) {
|
755
759
|
var included_in = module.$$dep,
|
756
760
|
body = module.$$proto[jsid],
|
@@ -802,34 +806,33 @@
|
|
802
806
|
}
|
803
807
|
};
|
804
808
|
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
*/
|
809
|
+
// Methods stubs are used to facilitate method_missing in opal. A stub is a
|
810
|
+
// placeholder function which just calls `method_missing` on the receiver.
|
811
|
+
// If no method with the given name is actually defined on an object, then it
|
812
|
+
// is obvious to say that the stub will be called instead, and then in turn
|
813
|
+
// method_missing will be called.
|
814
|
+
//
|
815
|
+
// When a file in ruby gets compiled to javascript, it includes a call to
|
816
|
+
// this function which adds stubs for every method name in the compiled file.
|
817
|
+
// It should then be safe to assume that method_missing will work for any
|
818
|
+
// method call detected.
|
819
|
+
//
|
820
|
+
// Method stubs are added to the BasicObject prototype, which every other
|
821
|
+
// ruby object inherits, so all objects should handle method missing. A stub
|
822
|
+
// is only added if the given property name (method name) is not already
|
823
|
+
// defined.
|
824
|
+
//
|
825
|
+
// Note: all ruby methods have a `$` prefix in javascript, so all stubs will
|
826
|
+
// have this prefix as well (to make this method more performant).
|
827
|
+
//
|
828
|
+
// Opal.add_stubs(["$foo", "$bar", "$baz="]);
|
829
|
+
//
|
830
|
+
// All stub functions will have a private `$$stub` property set to true so
|
831
|
+
// that other internal methods can detect if a method is just a stub or not.
|
832
|
+
// `Kernel#respond_to?` uses this property to detect a methods presence.
|
833
|
+
//
|
834
|
+
// @param [Array] stubs an array of method stubs to add
|
835
|
+
//
|
833
836
|
Opal.add_stubs = function(stubs) {
|
834
837
|
var subscriber, subscribers = Opal.stub_subscribers,
|
835
838
|
i, ilength = stubs.length,
|
@@ -850,30 +853,27 @@
|
|
850
853
|
}
|
851
854
|
};
|
852
855
|
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
*/
|
867
|
-
function add_stub_for(prototype, stub) {
|
856
|
+
// Keep a list of prototypes that want method_missing stubs to be added.
|
857
|
+
//
|
858
|
+
// @default [Prototype List] BasicObject_alloc.prototype
|
859
|
+
//
|
860
|
+
Opal.stub_subscribers = [BasicObject_alloc.prototype];
|
861
|
+
|
862
|
+
// Add a method_missing stub function to the given prototype for the
|
863
|
+
// given name.
|
864
|
+
//
|
865
|
+
// @param [Prototype] prototype the target prototype
|
866
|
+
// @param [String] stub stub name to add (e.g. "$foo")
|
867
|
+
//
|
868
|
+
Opal.add_stub_for = function(prototype, stub) {
|
868
869
|
var method_missing_stub = stub_for(stub);
|
869
870
|
prototype[stub] = method_missing_stub;
|
870
871
|
}
|
871
872
|
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
*/
|
873
|
+
// Generate the method_missing stub for a given method name.
|
874
|
+
//
|
875
|
+
// @param [String] method_name The js-name of the method to stub (e.g. "$foo")
|
876
|
+
//
|
877
877
|
function stub_for(method_name) {
|
878
878
|
function method_missing_stub() {
|
879
879
|
// Copy any given block onto the method_missing dispatcher
|
@@ -891,9 +891,6 @@
|
|
891
891
|
return method_missing_stub;
|
892
892
|
}
|
893
893
|
|
894
|
-
// Expose for other parts of Opal to use
|
895
|
-
Opal.add_stub_for = add_stub_for;
|
896
|
-
|
897
894
|
// Arity count error dispatcher
|
898
895
|
Opal.ac = function(actual, expected, object, meth) {
|
899
896
|
var inspect = '';
|
@@ -908,6 +905,23 @@
|
|
908
905
|
throw Opal.ArgumentError.$new('[' + inspect + '] wrong number of arguments(' + actual + ' for ' + expected + ')');
|
909
906
|
};
|
910
907
|
|
908
|
+
// The Array of ancestors for a given module/class
|
909
|
+
Opal.ancestors = function(module_or_class) {
|
910
|
+
var parent = module_or_class,
|
911
|
+
result = [];
|
912
|
+
|
913
|
+
while (parent) {
|
914
|
+
result.push(parent);
|
915
|
+
for (var i=0; i < parent.$$inc.length; i++) {
|
916
|
+
result = result.concat(Opal.ancestors(parent.$$inc[i]));
|
917
|
+
}
|
918
|
+
|
919
|
+
parent = parent.$$is_class ? parent.$$super : null;
|
920
|
+
}
|
921
|
+
|
922
|
+
return result;
|
923
|
+
}
|
924
|
+
|
911
925
|
// Super dispatcher
|
912
926
|
Opal.find_super_dispatcher = function(obj, jsid, current_func, iter, defs) {
|
913
927
|
var dispatcher;
|
@@ -980,14 +994,13 @@
|
|
980
994
|
return klass.$$proto;
|
981
995
|
};
|
982
996
|
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
*/
|
997
|
+
// Used to return as an expression. Sometimes, we can't simply return from
|
998
|
+
// a javascript function as if we were a method, as the return is used as
|
999
|
+
// an expression, or even inside a block which must "return" to the outer
|
1000
|
+
// method. This helper simply throws an error which is then caught by the
|
1001
|
+
// method. This approach is expensive, so it is only used when absolutely
|
1002
|
+
// needed.
|
1003
|
+
//
|
991
1004
|
Opal.ret = function(val) {
|
992
1005
|
Opal.returner.$v = val;
|
993
1006
|
throw Opal.returner;
|
@@ -1071,13 +1084,28 @@
|
|
1071
1084
|
return false;
|
1072
1085
|
};
|
1073
1086
|
|
1074
|
-
//
|
1087
|
+
// Helpers for implementing multiple assignment
|
1088
|
+
// Our code for extracting the values and assigning them only works if the
|
1089
|
+
// return value is a JS array
|
1090
|
+
// So if we get an Array subclass, extract the wrapped JS array from it
|
1091
|
+
|
1075
1092
|
Opal.to_ary = function(value) {
|
1093
|
+
// Used for: a, b = something (no splat)
|
1076
1094
|
if (value.$$is_array) {
|
1077
|
-
return value;
|
1095
|
+
return (value.constructor === Array) ? value : value.literal;
|
1078
1096
|
}
|
1079
|
-
else if (value
|
1080
|
-
|
1097
|
+
else if (value['$respond_to?']('to_ary', true)) {
|
1098
|
+
var ary = value.$to_ary();
|
1099
|
+
if (ary === nil) {
|
1100
|
+
return [value];
|
1101
|
+
}
|
1102
|
+
else if (ary.$$is_array) {
|
1103
|
+
return (ary.constructor === Array) ? ary : ary.literal;
|
1104
|
+
}
|
1105
|
+
else {
|
1106
|
+
throw Opal.TypeError.$new("Can't convert " + value.$$class +
|
1107
|
+
" to Array (" + value.$$class + "#to_ary gives " + ary.$$class + ")");
|
1108
|
+
}
|
1081
1109
|
}
|
1082
1110
|
else {
|
1083
1111
|
return [value];
|
@@ -1085,34 +1113,45 @@
|
|
1085
1113
|
};
|
1086
1114
|
|
1087
1115
|
Opal.to_a = function(value) {
|
1088
|
-
|
1089
|
-
|
1116
|
+
// Used for: a, b = *something (with splat)
|
1117
|
+
if (value.$$is_array) {
|
1118
|
+
// A splatted array must be copied
|
1119
|
+
return (value.constructor === Array) ? value.slice() : value.literal.slice();
|
1090
1120
|
}
|
1091
|
-
else if (value
|
1092
|
-
|
1121
|
+
else if (value['$respond_to?']('to_a', true)) {
|
1122
|
+
var ary = value.$to_a();
|
1123
|
+
if (ary === nil) {
|
1124
|
+
return [value];
|
1125
|
+
}
|
1126
|
+
else if (ary.$$is_array) {
|
1127
|
+
return (ary.constructor === Array) ? ary : ary.literal;
|
1128
|
+
}
|
1129
|
+
else {
|
1130
|
+
throw Opal.TypeError.$new("Can't convert " + value.$$class +
|
1131
|
+
" to Array (" + value.$$class + "#to_a gives " + ary.$$class + ")");
|
1132
|
+
}
|
1093
1133
|
}
|
1094
1134
|
else {
|
1095
1135
|
return [value];
|
1096
1136
|
}
|
1097
1137
|
};
|
1098
1138
|
|
1099
|
-
|
1100
|
-
|
1101
|
-
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1107
|
-
|
1108
|
-
|
1109
|
-
|
1110
|
-
*/
|
1139
|
+
// Used to get a list of rest keyword arguments. Method takes the given
|
1140
|
+
// keyword args, i.e. the hash literal passed to the method containing all
|
1141
|
+
// keyword arguemnts passed to method, as well as the used args which are
|
1142
|
+
// the names of required and optional arguments defined. This method then
|
1143
|
+
// just returns all key/value pairs which have not been used, in a new
|
1144
|
+
// hash literal.
|
1145
|
+
//
|
1146
|
+
// @param given_args [Hash] all kwargs given to method
|
1147
|
+
// @param used_args [Object<String: true>] all keys used as named kwargs
|
1148
|
+
// @return [Hash]
|
1149
|
+
//
|
1111
1150
|
Opal.kwrestargs = function(given_args, used_args) {
|
1112
1151
|
var keys = [],
|
1113
1152
|
map = {},
|
1114
1153
|
key = null,
|
1115
|
-
given_map = given_args
|
1154
|
+
given_map = given_args.$$smap;
|
1116
1155
|
|
1117
1156
|
for (key in given_map) {
|
1118
1157
|
if (!used_args[key]) {
|
@@ -1124,21 +1163,20 @@
|
|
1124
1163
|
return Opal.hash2(keys, map);
|
1125
1164
|
};
|
1126
1165
|
|
1127
|
-
|
1128
|
-
|
1129
|
-
|
1130
|
-
|
1131
|
-
|
1132
|
-
|
1133
|
-
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
1138
|
-
|
1139
|
-
|
1140
|
-
|
1141
|
-
*/
|
1166
|
+
// Call a ruby method on a ruby object with some arguments:
|
1167
|
+
//
|
1168
|
+
// var my_array = [1, 2, 3, 4]
|
1169
|
+
// Opal.send(my_array, 'length') # => 4
|
1170
|
+
// Opal.send(my_array, 'reverse!') # => [4, 3, 2, 1]
|
1171
|
+
//
|
1172
|
+
// A missing method will be forwarded to the object via
|
1173
|
+
// method_missing.
|
1174
|
+
//
|
1175
|
+
// The result of either call with be returned.
|
1176
|
+
//
|
1177
|
+
// @param [Object] recv the ruby object
|
1178
|
+
// @param [String] mid ruby method to call
|
1179
|
+
//
|
1142
1180
|
Opal.send = function(recv, mid) {
|
1143
1181
|
var args = $slice.call(arguments, 2),
|
1144
1182
|
func = recv['$' + mid];
|
@@ -1162,43 +1200,42 @@
|
|
1162
1200
|
return recv.$method_missing.apply(recv, [mid].concat(args));
|
1163
1201
|
};
|
1164
1202
|
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
1173
|
-
|
1174
|
-
|
1175
|
-
|
1176
|
-
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
|
1193
|
-
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
*/
|
1203
|
+
// Used to define methods on an object. This is a helper method, used by the
|
1204
|
+
// compiled source to define methods on special case objects when the compiler
|
1205
|
+
// can not determine the destination object, or the object is a Module
|
1206
|
+
// instance. This can get called by `Module#define_method` as well.
|
1207
|
+
//
|
1208
|
+
// ## Modules
|
1209
|
+
//
|
1210
|
+
// Any method defined on a module will come through this runtime helper.
|
1211
|
+
// The method is added to the module body, and the owner of the method is
|
1212
|
+
// set to be the module itself. This is used later when choosing which
|
1213
|
+
// method should show on a class if more than 1 included modules define
|
1214
|
+
// the same method. Finally, if the module is in `module_function` mode,
|
1215
|
+
// then the method is also defined onto the module itself.
|
1216
|
+
//
|
1217
|
+
// ## Classes
|
1218
|
+
//
|
1219
|
+
// This helper will only be called for classes when a method is being
|
1220
|
+
// defined indirectly; either through `Module#define_method`, or by a
|
1221
|
+
// literal `def` method inside an `instance_eval` or `class_eval` body. In
|
1222
|
+
// either case, the method is simply added to the class' prototype. A special
|
1223
|
+
// exception exists for `BasicObject` and `Object`. These two classes are
|
1224
|
+
// special because they are used in toll-free bridged classes. In each of
|
1225
|
+
// these two cases, extra work is required to define the methods on toll-free
|
1226
|
+
// bridged class' prototypes as well.
|
1227
|
+
//
|
1228
|
+
// ## Objects
|
1229
|
+
//
|
1230
|
+
// If a simple ruby object is the object, then the method is simply just
|
1231
|
+
// defined on the object as a singleton method. This would be the case when
|
1232
|
+
// a method is defined inside an `instance_eval` block.
|
1233
|
+
//
|
1234
|
+
// @param [RubyObject or Class] obj the actual obj to define method for
|
1235
|
+
// @param [String] jsid the javascript friendly method name (e.g. '$foo')
|
1236
|
+
// @param [Function] body the literal javascript function used as method
|
1237
|
+
// @return [null]
|
1238
|
+
//
|
1202
1239
|
Opal.defn = function(obj, jsid, body) {
|
1203
1240
|
obj.$$proto[jsid] = body;
|
1204
1241
|
|
@@ -1215,7 +1252,7 @@
|
|
1215
1252
|
|
1216
1253
|
if (bridged) {
|
1217
1254
|
for (var i = bridged.length - 1; i >= 0; i--) {
|
1218
|
-
|
1255
|
+
bridge_method(bridged[i], obj, jsid, body);
|
1219
1256
|
}
|
1220
1257
|
}
|
1221
1258
|
}
|
@@ -1232,9 +1269,8 @@
|
|
1232
1269
|
return nil;
|
1233
1270
|
};
|
1234
1271
|
|
1235
|
-
|
1236
|
-
|
1237
|
-
*/
|
1272
|
+
|
1273
|
+
// Define a singleton method on the given object.
|
1238
1274
|
Opal.defs = function(obj, jsid, body) {
|
1239
1275
|
Opal.defn(Opal.get_singleton_class(obj), jsid, body)
|
1240
1276
|
};
|
@@ -1249,9 +1285,7 @@
|
|
1249
1285
|
}
|
1250
1286
|
};
|
1251
1287
|
|
1252
|
-
|
1253
|
-
* Called from #remove_method.
|
1254
|
-
*/
|
1288
|
+
// Called from #remove_method.
|
1255
1289
|
Opal.rdef = function(obj, jsid) {
|
1256
1290
|
// TODO: remove from bridges as well
|
1257
1291
|
|
@@ -1273,9 +1307,7 @@
|
|
1273
1307
|
}
|
1274
1308
|
};
|
1275
1309
|
|
1276
|
-
|
1277
|
-
* Called from #undef_method.
|
1278
|
-
*/
|
1310
|
+
// Called from #undef_method.
|
1279
1311
|
Opal.udef = function(obj, jsid) {
|
1280
1312
|
if (!obj.$$proto[jsid] || obj.$$proto[jsid].$$stub) {
|
1281
1313
|
throw Opal.NameError.$new("method '" + jsid.substr(1) + "' not defined in " + obj.$name());
|
@@ -1295,33 +1327,11 @@
|
|
1295
1327
|
}
|
1296
1328
|
};
|
1297
1329
|
|
1298
|
-
// This black magic is required to avoid clashes of internal special fields,
|
1299
|
-
// like $$donated.
|
1300
|
-
function wrap(body) {
|
1301
|
-
function alias() {
|
1302
|
-
body.$$p = alias.$$p;
|
1303
|
-
body.$$s = alias.$$s;
|
1304
|
-
|
1305
|
-
try {
|
1306
|
-
return body.apply(this, $slice.call(arguments));
|
1307
|
-
}
|
1308
|
-
finally {
|
1309
|
-
alias.$$s = null;
|
1310
|
-
alias.$$p = null;
|
1311
|
-
}
|
1312
|
-
}
|
1313
|
-
|
1314
|
-
alias.$$target = body;
|
1315
|
-
alias.$$arity = body.length;
|
1316
|
-
|
1317
|
-
return alias;
|
1318
|
-
}
|
1319
|
-
|
1320
1330
|
Opal.alias = function(obj, name, old) {
|
1321
1331
|
var id = '$' + name,
|
1322
1332
|
old_id = '$' + old,
|
1323
1333
|
body = obj.$$proto['$' + old];
|
1324
|
-
|
1334
|
+
|
1325
1335
|
// instance_eval is being run on a class/module, so that need to alias class methods
|
1326
1336
|
if (obj.$$eval) {
|
1327
1337
|
return Opal.alias(Opal.get_singleton_class(obj), name, old);
|
@@ -1340,7 +1350,7 @@
|
|
1340
1350
|
}
|
1341
1351
|
}
|
1342
1352
|
|
1343
|
-
Opal.defn(obj, id,
|
1353
|
+
Opal.defn(obj, id, body);
|
1344
1354
|
|
1345
1355
|
return obj;
|
1346
1356
|
};
|
@@ -1353,26 +1363,26 @@
|
|
1353
1363
|
throw Opal.NameError.$new("undefined native method `" + native_name + "' for class `" + obj.$name() + "'")
|
1354
1364
|
}
|
1355
1365
|
|
1356
|
-
Opal.defn(obj, id,
|
1366
|
+
Opal.defn(obj, id, body);
|
1357
1367
|
|
1358
1368
|
return obj;
|
1359
1369
|
};
|
1360
1370
|
|
1361
|
-
Opal.hash_init = function
|
1362
|
-
hash
|
1363
|
-
hash
|
1364
|
-
hash
|
1371
|
+
Opal.hash_init = function(hash) {
|
1372
|
+
hash.$$map = {};
|
1373
|
+
hash.$$smap = {};
|
1374
|
+
hash.$$keys = [];
|
1365
1375
|
};
|
1366
1376
|
|
1367
|
-
Opal.hash_clone = function
|
1377
|
+
Opal.hash_clone = function(from_hash, to_hash) {
|
1368
1378
|
to_hash.none = from_hash.none;
|
1369
1379
|
to_hash.proc = from_hash.proc;
|
1370
1380
|
|
1371
|
-
for (var i = 0, keys = from_hash
|
1372
|
-
key = from_hash
|
1381
|
+
for (var i = 0, keys = from_hash.$$keys, length = keys.length, key, value; i < length; i++) {
|
1382
|
+
key = from_hash.$$keys[i];
|
1373
1383
|
|
1374
1384
|
if (key.$$is_string) {
|
1375
|
-
value = from_hash
|
1385
|
+
value = from_hash.$$smap[key];
|
1376
1386
|
} else {
|
1377
1387
|
value = key.value;
|
1378
1388
|
key = key.key;
|
@@ -1382,25 +1392,25 @@
|
|
1382
1392
|
}
|
1383
1393
|
};
|
1384
1394
|
|
1385
|
-
Opal.hash_put = function
|
1395
|
+
Opal.hash_put = function(hash, key, value) {
|
1386
1396
|
if (key.$$is_string) {
|
1387
|
-
if (!hash
|
1388
|
-
hash
|
1397
|
+
if (!hash.$$smap.hasOwnProperty(key)) {
|
1398
|
+
hash.$$keys.push(key);
|
1389
1399
|
}
|
1390
|
-
hash
|
1400
|
+
hash.$$smap[key] = value;
|
1391
1401
|
return;
|
1392
1402
|
}
|
1393
1403
|
|
1394
1404
|
var key_hash = key.$hash(), bucket, last_bucket;
|
1395
1405
|
|
1396
|
-
if (!hash
|
1406
|
+
if (!hash.$$map.hasOwnProperty(key_hash)) {
|
1397
1407
|
bucket = {key: key, key_hash: key_hash, value: value};
|
1398
|
-
hash
|
1399
|
-
hash
|
1408
|
+
hash.$$keys.push(bucket);
|
1409
|
+
hash.$$map[key_hash] = bucket;
|
1400
1410
|
return;
|
1401
1411
|
}
|
1402
1412
|
|
1403
|
-
bucket = hash
|
1413
|
+
bucket = hash.$$map[key_hash];
|
1404
1414
|
|
1405
1415
|
while (bucket) {
|
1406
1416
|
if (key === bucket.key || key['$eql?'](bucket.key)) {
|
@@ -1414,23 +1424,23 @@
|
|
1414
1424
|
|
1415
1425
|
if (last_bucket) {
|
1416
1426
|
bucket = {key: key, key_hash: key_hash, value: value};
|
1417
|
-
hash
|
1427
|
+
hash.$$keys.push(bucket);
|
1418
1428
|
last_bucket.next = bucket;
|
1419
1429
|
}
|
1420
1430
|
};
|
1421
1431
|
|
1422
|
-
Opal.hash_get = function
|
1432
|
+
Opal.hash_get = function(hash, key) {
|
1423
1433
|
if (key.$$is_string) {
|
1424
|
-
if (hash
|
1425
|
-
return hash
|
1434
|
+
if (hash.$$smap.hasOwnProperty(key)) {
|
1435
|
+
return hash.$$smap[key];
|
1426
1436
|
}
|
1427
1437
|
return;
|
1428
1438
|
}
|
1429
1439
|
|
1430
1440
|
var key_hash = key.$hash(), bucket;
|
1431
1441
|
|
1432
|
-
if (hash
|
1433
|
-
bucket = hash
|
1442
|
+
if (hash.$$map.hasOwnProperty(key_hash)) {
|
1443
|
+
bucket = hash.$$map[key_hash];
|
1434
1444
|
|
1435
1445
|
while (bucket) {
|
1436
1446
|
if (key === bucket.key || key['$eql?'](bucket.key)) {
|
@@ -1441,11 +1451,11 @@
|
|
1441
1451
|
}
|
1442
1452
|
};
|
1443
1453
|
|
1444
|
-
Opal.hash_delete = function
|
1445
|
-
var i, keys = hash
|
1454
|
+
Opal.hash_delete = function(hash, key) {
|
1455
|
+
var i, keys = hash.$$keys, length = keys.length, value;
|
1446
1456
|
|
1447
1457
|
if (key.$$is_string) {
|
1448
|
-
if (!hash
|
1458
|
+
if (!hash.$$smap.hasOwnProperty(key)) {
|
1449
1459
|
return;
|
1450
1460
|
}
|
1451
1461
|
|
@@ -1456,18 +1466,18 @@
|
|
1456
1466
|
}
|
1457
1467
|
}
|
1458
1468
|
|
1459
|
-
value = hash
|
1460
|
-
delete hash
|
1469
|
+
value = hash.$$smap[key];
|
1470
|
+
delete hash.$$smap[key];
|
1461
1471
|
return value;
|
1462
1472
|
}
|
1463
1473
|
|
1464
1474
|
var key_hash = key.$hash();
|
1465
1475
|
|
1466
|
-
if (!hash
|
1476
|
+
if (!hash.$$map.hasOwnProperty(key_hash)) {
|
1467
1477
|
return;
|
1468
1478
|
}
|
1469
1479
|
|
1470
|
-
var bucket = hash
|
1480
|
+
var bucket = hash.$$map[key_hash], last_bucket;
|
1471
1481
|
|
1472
1482
|
while (bucket) {
|
1473
1483
|
if (key === bucket.key || key['$eql?'](bucket.key)) {
|
@@ -1487,10 +1497,10 @@
|
|
1487
1497
|
delete last_bucket.next;
|
1488
1498
|
}
|
1489
1499
|
else if (bucket.next) {
|
1490
|
-
hash
|
1500
|
+
hash.$$map[key_hash] = bucket.next;
|
1491
1501
|
}
|
1492
1502
|
else {
|
1493
|
-
delete hash
|
1503
|
+
delete hash.$$map[key_hash];
|
1494
1504
|
}
|
1495
1505
|
|
1496
1506
|
return value;
|
@@ -1500,24 +1510,24 @@
|
|
1500
1510
|
}
|
1501
1511
|
};
|
1502
1512
|
|
1503
|
-
Opal.hash_rehash = function
|
1504
|
-
for (var i = 0, length = hash
|
1513
|
+
Opal.hash_rehash = function(hash) {
|
1514
|
+
for (var i = 0, length = hash.$$keys.length, key_hash, bucket, last_bucket; i < length; i++) {
|
1505
1515
|
|
1506
|
-
if (hash
|
1516
|
+
if (hash.$$keys[i].$$is_string) {
|
1507
1517
|
continue;
|
1508
1518
|
}
|
1509
1519
|
|
1510
|
-
key_hash = hash
|
1520
|
+
key_hash = hash.$$keys[i].key.$hash();
|
1511
1521
|
|
1512
|
-
if (key_hash === hash
|
1522
|
+
if (key_hash === hash.$$keys[i].key_hash) {
|
1513
1523
|
continue;
|
1514
1524
|
}
|
1515
1525
|
|
1516
|
-
bucket = hash
|
1526
|
+
bucket = hash.$$map[hash.$$keys[i].key_hash];
|
1517
1527
|
last_bucket = undefined;
|
1518
1528
|
|
1519
1529
|
while (bucket) {
|
1520
|
-
if (bucket === hash
|
1530
|
+
if (bucket === hash.$$keys[i]) {
|
1521
1531
|
if (last_bucket && bucket.next) {
|
1522
1532
|
last_bucket.next = bucket.next;
|
1523
1533
|
}
|
@@ -1525,10 +1535,10 @@
|
|
1525
1535
|
delete last_bucket.next;
|
1526
1536
|
}
|
1527
1537
|
else if (bucket.next) {
|
1528
|
-
hash
|
1538
|
+
hash.$$map[hash.$$keys[i].key_hash] = bucket.next;
|
1529
1539
|
}
|
1530
1540
|
else {
|
1531
|
-
delete hash
|
1541
|
+
delete hash.$$map[hash.$$keys[i].key_hash];
|
1532
1542
|
}
|
1533
1543
|
break;
|
1534
1544
|
}
|
@@ -1536,18 +1546,18 @@
|
|
1536
1546
|
bucket = bucket.next;
|
1537
1547
|
}
|
1538
1548
|
|
1539
|
-
hash
|
1549
|
+
hash.$$keys[i].key_hash = key_hash;
|
1540
1550
|
|
1541
|
-
if (!hash
|
1542
|
-
hash
|
1551
|
+
if (!hash.$$map.hasOwnProperty(key_hash)) {
|
1552
|
+
hash.$$map[key_hash] = hash.$$keys[i];
|
1543
1553
|
continue;
|
1544
1554
|
}
|
1545
1555
|
|
1546
|
-
bucket = hash
|
1556
|
+
bucket = hash.$$map[key_hash];
|
1547
1557
|
last_bucket = undefined;
|
1548
1558
|
|
1549
1559
|
while (bucket) {
|
1550
|
-
if (bucket === hash
|
1560
|
+
if (bucket === hash.$$keys[i]) {
|
1551
1561
|
last_bucket = undefined;
|
1552
1562
|
break;
|
1553
1563
|
}
|
@@ -1556,7 +1566,7 @@
|
|
1556
1566
|
}
|
1557
1567
|
|
1558
1568
|
if (last_bucket) {
|
1559
|
-
last_bucket.next = hash
|
1569
|
+
last_bucket.next = hash.$$keys[i];
|
1560
1570
|
}
|
1561
1571
|
}
|
1562
1572
|
};
|
@@ -1616,26 +1626,24 @@
|
|
1616
1626
|
return hash;
|
1617
1627
|
};
|
1618
1628
|
|
1619
|
-
|
1620
|
-
|
1621
|
-
|
1622
|
-
|
1623
|
-
|
1624
|
-
*/
|
1629
|
+
// hash2 is a faster creator for hashes that just use symbols and
|
1630
|
+
// strings as keys. The map and keys array can be constructed at
|
1631
|
+
// compile time, so they are just added here by the constructor
|
1632
|
+
// function
|
1633
|
+
//
|
1625
1634
|
Opal.hash2 = function(keys, smap) {
|
1626
1635
|
var hash = new Opal.Hash.$$alloc();
|
1627
1636
|
|
1628
|
-
hash
|
1629
|
-
hash
|
1630
|
-
hash
|
1637
|
+
hash.$$map = {};
|
1638
|
+
hash.$$keys = keys;
|
1639
|
+
hash.$$smap = smap;
|
1631
1640
|
|
1632
1641
|
return hash;
|
1633
1642
|
};
|
1634
1643
|
|
1635
|
-
|
1636
|
-
|
1637
|
-
|
1638
|
-
*/
|
1644
|
+
// Create a new range instance with first and last values, and whether the
|
1645
|
+
// range excludes the last value.
|
1646
|
+
//
|
1639
1647
|
Opal.range = function(first, last, exc) {
|
1640
1648
|
var range = new Opal.Range.$$alloc();
|
1641
1649
|
range.begin = first;
|
@@ -1646,17 +1654,19 @@
|
|
1646
1654
|
};
|
1647
1655
|
|
1648
1656
|
Opal.ivar = function(name) {
|
1649
|
-
if (
|
1650
|
-
|
1651
|
-
name === "
|
1657
|
+
if (
|
1658
|
+
// properties
|
1659
|
+
name === "constructor" ||
|
1660
|
+
name === "displayName" ||
|
1661
|
+
name === "__count__" ||
|
1652
1662
|
name === "__noSuchMethod__" ||
|
1653
|
-
name === "
|
1654
|
-
|
1655
|
-
return name + "$";
|
1656
|
-
}
|
1663
|
+
name === "__parent__" ||
|
1664
|
+
name === "__proto__" ||
|
1657
1665
|
|
1658
|
-
|
1659
|
-
name === "
|
1666
|
+
// methods
|
1667
|
+
name === "hasOwnProperty" ||
|
1668
|
+
name === "valueOf"
|
1669
|
+
)
|
1660
1670
|
{
|
1661
1671
|
return name + "$";
|
1662
1672
|
}
|
@@ -1666,169 +1676,133 @@
|
|
1666
1676
|
|
1667
1677
|
// Require system
|
1668
1678
|
// --------------
|
1669
|
-
(function(Opal) {
|
1670
|
-
var loaded_features = ['corelib/runtime'],
|
1671
|
-
require_table = {'corelib/runtime': true},
|
1672
|
-
modules = {};
|
1673
1679
|
|
1674
|
-
|
1680
|
+
Opal.modules = {};
|
1681
|
+
Opal.loaded_features = ['corelib/runtime'];
|
1682
|
+
Opal.current_dir = '.'
|
1683
|
+
Opal.require_table = {'corelib/runtime': true};
|
1675
1684
|
|
1676
|
-
|
1677
|
-
|
1685
|
+
function normalize(path) {
|
1686
|
+
var parts, part, new_parts = [], SEPARATOR = '/';
|
1678
1687
|
|
1679
|
-
|
1680
|
-
|
1681
|
-
|
1682
|
-
|
1683
|
-
path = path.replace(/\.(rb|opal|js)$/, '');
|
1684
|
-
parts = path.split(SEPARATOR);
|
1688
|
+
if (Opal.current_dir !== '.') {
|
1689
|
+
path = Opal.current_dir.replace(/\/*$/, '/') + path;
|
1690
|
+
}
|
1685
1691
|
|
1686
|
-
|
1687
|
-
|
1688
|
-
if (part === '') continue;
|
1689
|
-
(part === '..') ? new_parts.pop() : new_parts.push(part)
|
1690
|
-
}
|
1692
|
+
path = path.replace(/\.(rb|opal|js)$/, '');
|
1693
|
+
parts = path.split(SEPARATOR);
|
1691
1694
|
|
1692
|
-
|
1695
|
+
for (var i = 0, ii = parts.length; i < ii; i++) {
|
1696
|
+
part = parts[i];
|
1697
|
+
if (part === '') continue;
|
1698
|
+
(part === '..') ? new_parts.pop() : new_parts.push(part)
|
1693
1699
|
}
|
1694
1700
|
|
1695
|
-
|
1696
|
-
|
1701
|
+
return new_parts.join(SEPARATOR);
|
1702
|
+
}
|
1697
1703
|
|
1698
|
-
|
1699
|
-
|
1704
|
+
Opal.loaded = function(paths) {
|
1705
|
+
var i, l, path;
|
1700
1706
|
|
1701
|
-
|
1702
|
-
|
1703
|
-
}
|
1707
|
+
for (i = 0, l = paths.length; i < l; i++) {
|
1708
|
+
path = normalize(paths[i]);
|
1704
1709
|
|
1705
|
-
|
1706
|
-
|
1710
|
+
if (Opal.require_table[path]) {
|
1711
|
+
return;
|
1707
1712
|
}
|
1713
|
+
|
1714
|
+
Opal.loaded_features.push(path);
|
1715
|
+
Opal.require_table[path] = true;
|
1708
1716
|
}
|
1717
|
+
}
|
1709
1718
|
|
1710
|
-
|
1711
|
-
|
1719
|
+
Opal.load = function(path) {
|
1720
|
+
path = normalize(path);
|
1712
1721
|
|
1713
|
-
|
1722
|
+
Opal.loaded([path]);
|
1714
1723
|
|
1715
|
-
|
1724
|
+
var module = Opal.modules[path];
|
1716
1725
|
|
1717
|
-
|
1718
|
-
|
1719
|
-
|
1720
|
-
|
1721
|
-
|
1722
|
-
|
1726
|
+
if (module) {
|
1727
|
+
module(Opal);
|
1728
|
+
}
|
1729
|
+
else {
|
1730
|
+
var severity = Opal.dynamic_require_severity || 'warning';
|
1731
|
+
var message = 'cannot load such file -- ' + path;
|
1723
1732
|
|
1724
|
-
|
1725
|
-
|
1726
|
-
|
1727
|
-
|
1728
|
-
|
1729
|
-
}
|
1733
|
+
if (severity === "error") {
|
1734
|
+
Opal.LoadError ? Opal.LoadError.$new(message) : function(){throw message}();
|
1735
|
+
}
|
1736
|
+
else if (severity === "warning") {
|
1737
|
+
console.warn('WARNING: LoadError: ' + message);
|
1730
1738
|
}
|
1731
|
-
|
1732
|
-
return true;
|
1733
1739
|
}
|
1734
1740
|
|
1735
|
-
|
1736
|
-
|
1741
|
+
return true;
|
1742
|
+
}
|
1737
1743
|
|
1738
|
-
|
1739
|
-
|
1740
|
-
}
|
1744
|
+
Opal.require = function(path) {
|
1745
|
+
path = normalize(path);
|
1741
1746
|
|
1742
|
-
|
1747
|
+
if (Opal.require_table[path]) {
|
1748
|
+
return false;
|
1743
1749
|
}
|
1744
1750
|
|
1745
|
-
Opal.
|
1746
|
-
|
1747
|
-
Opal.loaded = loaded;
|
1748
|
-
|
1749
|
-
Opal.load = load;
|
1750
|
-
Opal.require = require;
|
1751
|
-
})(Opal);
|
1751
|
+
return Opal.load(path);
|
1752
|
+
}
|
1752
1753
|
|
1753
1754
|
// Initialization
|
1754
1755
|
// --------------
|
1755
1756
|
|
1756
|
-
// The actual class for BasicObject
|
1757
|
-
var BasicObjectClass;
|
1758
|
-
|
1759
|
-
// The actual Object class
|
1760
|
-
var ObjectClass;
|
1761
|
-
|
1762
|
-
// The actual Module class
|
1763
|
-
var ModuleClass;
|
1764
|
-
|
1765
|
-
// The actual Class class
|
1766
|
-
var ClassClass;
|
1767
|
-
|
1768
|
-
// Constructor for instances of BasicObject
|
1769
|
-
function BasicObject(){}
|
1770
|
-
|
1771
|
-
// Constructor for instances of Object
|
1772
|
-
function Object(){}
|
1773
|
-
|
1774
|
-
// Constructor for instances of Class
|
1775
|
-
function Class(){}
|
1776
|
-
|
1777
|
-
// Constructor for instances of Module
|
1778
|
-
function Module(){}
|
1779
|
-
|
1780
|
-
// Constructor for instances of NilClass (nil)
|
1781
|
-
function NilClass(){}
|
1782
|
-
|
1783
1757
|
// Constructors for *instances* of core objects
|
1784
|
-
boot_class_alloc('BasicObject',
|
1785
|
-
boot_class_alloc('Object',
|
1786
|
-
boot_class_alloc('Module',
|
1787
|
-
boot_class_alloc('Class',
|
1758
|
+
boot_class_alloc('BasicObject', BasicObject_alloc);
|
1759
|
+
boot_class_alloc('Object', Object_alloc, BasicObject_alloc);
|
1760
|
+
boot_class_alloc('Module', Module_alloc, Object_alloc);
|
1761
|
+
boot_class_alloc('Class', Class_alloc, Module_alloc);
|
1788
1762
|
|
1789
1763
|
// Constructors for *classes* of core objects
|
1790
|
-
|
1791
|
-
|
1792
|
-
|
1793
|
-
|
1764
|
+
BasicObject = boot_core_class_object('BasicObject', BasicObject_alloc, Class_alloc);
|
1765
|
+
_Object = boot_core_class_object('Object', Object_alloc, BasicObject.constructor);
|
1766
|
+
Module = boot_core_class_object('Module', Module_alloc, _Object.constructor);
|
1767
|
+
Class = boot_core_class_object('Class', Class_alloc, Module.constructor);
|
1794
1768
|
|
1795
1769
|
// Fix booted classes to use their metaclass
|
1796
|
-
|
1797
|
-
|
1798
|
-
|
1799
|
-
|
1770
|
+
BasicObject.$$class = Class;
|
1771
|
+
_Object.$$class = Class;
|
1772
|
+
Module.$$class = Class;
|
1773
|
+
Class.$$class = Class;
|
1800
1774
|
|
1801
1775
|
// Fix superclasses of booted classes
|
1802
|
-
|
1803
|
-
|
1804
|
-
|
1805
|
-
|
1806
|
-
|
1807
|
-
|
1808
|
-
|
1809
|
-
|
1810
|
-
|
1811
|
-
|
1812
|
-
Opal.base
|
1813
|
-
|
1814
|
-
|
1815
|
-
|
1816
|
-
|
1817
|
-
|
1818
|
-
|
1819
|
-
|
1820
|
-
|
1821
|
-
|
1776
|
+
BasicObject.$$super = null;
|
1777
|
+
_Object.$$super = BasicObject;
|
1778
|
+
Module.$$super = _Object;
|
1779
|
+
Class.$$super = Module;
|
1780
|
+
|
1781
|
+
BasicObject.$$parent = null;
|
1782
|
+
_Object.$$parent = BasicObject;
|
1783
|
+
Module.$$parent = _Object;
|
1784
|
+
Class.$$parent = Module;
|
1785
|
+
|
1786
|
+
Opal.base = _Object;
|
1787
|
+
BasicObject.$$scope = _Object.$$scope = Opal;
|
1788
|
+
BasicObject.$$orig_scope = _Object.$$orig_scope = Opal;
|
1789
|
+
|
1790
|
+
Module.$$scope = _Object.$$scope;
|
1791
|
+
Module.$$orig_scope = _Object.$$orig_scope;
|
1792
|
+
Class.$$scope = _Object.$$scope;
|
1793
|
+
Class.$$orig_scope = _Object.$$orig_scope;
|
1794
|
+
|
1795
|
+
_Object.$$proto.toString = function() {
|
1822
1796
|
return this.$to_s();
|
1823
1797
|
};
|
1824
1798
|
|
1825
|
-
|
1799
|
+
_Object.$$proto.$require = Opal.require;
|
1826
1800
|
|
1827
|
-
Opal.top = new
|
1801
|
+
Opal.top = new _Object.$$alloc();
|
1828
1802
|
|
1829
1803
|
// Nil
|
1830
|
-
Opal.klass(
|
1831
|
-
|
1804
|
+
Opal.klass(_Object, _Object, 'NilClass', NilClass_alloc);
|
1805
|
+
nil = Opal.nil = new NilClass_alloc();
|
1832
1806
|
nil.$$id = nil_id;
|
1833
1807
|
nil.call = nil.apply = function() { throw Opal.LocalJumpError.$new('no block given'); };
|
1834
1808
|
|
@@ -1842,6 +1816,7 @@ if (typeof(global) !== 'undefined') {
|
|
1842
1816
|
global.Opal = this.Opal;
|
1843
1817
|
Opal.global = global;
|
1844
1818
|
}
|
1819
|
+
|
1845
1820
|
if (typeof(window) !== 'undefined') {
|
1846
1821
|
window.Opal = this.Opal;
|
1847
1822
|
Opal.global = window;
|