opal 1.1.1 → 1.2.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.codeclimate.yml +3 -2
- data/.github/ISSUE_TEMPLATE/bug-report.md +47 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- data/.github/workflows/build.yml +11 -5
- data/.gitignore +1 -0
- data/.jshintrc +1 -1
- data/Gemfile +0 -4
- data/HACKING.md +1 -1
- data/README.md +19 -15
- data/UNRELEASED.md +41 -0
- data/benchmark-ips/bm_array_unshift.rb +7 -0
- data/bin/opal-mspec +2 -0
- data/docs/compiler.md +1 -1
- data/examples/rack/Gemfile +0 -1
- data/examples/rack/Gemfile.lock +0 -4
- data/lib/opal/cli.rb +1 -0
- data/lib/opal/cli_options.rb +4 -0
- data/lib/opal/cli_runners/nodejs.rb +4 -0
- data/lib/opal/cli_runners/source-map-support-browser.js +3 -1
- data/lib/opal/cli_runners/source-map-support-node.js +3 -1
- data/lib/opal/cli_runners/source-map-support.js +3 -1
- data/lib/opal/compiler.rb +2 -2
- data/lib/opal/nodes/args/arity_check.rb +1 -0
- data/lib/opal/nodes/args/parameters.rb +6 -0
- data/lib/opal/nodes/class.rb +1 -13
- data/lib/opal/nodes/literal.rb +14 -7
- data/lib/opal/nodes/module.rb +13 -9
- data/lib/opal/nodes/variables.rb +13 -4
- data/lib/opal/nodes/while.rb +54 -17
- data/lib/opal/parser.rb +1 -5
- data/lib/opal/parser/patch.rb +34 -0
- data/lib/opal/repl.rb +7 -0
- data/lib/opal/rewriter.rb +2 -0
- data/lib/opal/rewriters/arguments.rb +4 -1
- data/lib/opal/rewriters/forward_args.rb +54 -0
- data/lib/opal/rewriters/logical_operator_assignment.rb +5 -2
- data/lib/opal/rewriters/opal_engine_check.rb +5 -7
- data/lib/opal/version.rb +1 -1
- data/opal/corelib/array.rb +42 -20
- data/opal/corelib/array/pack.rb +6 -1
- data/opal/corelib/complex.rb +2 -0
- data/opal/corelib/constants.rb +3 -3
- data/opal/corelib/hash.rb +36 -38
- data/opal/corelib/module.rb +2 -7
- data/opal/corelib/number.rb +2 -180
- data/opal/corelib/numeric.rb +156 -0
- data/opal/corelib/object_space.rb +102 -0
- data/opal/corelib/random.rb +31 -66
- data/opal/corelib/random/formatter.rb +122 -0
- data/opal/corelib/range.rb +50 -19
- data/opal/corelib/runtime.js +82 -21
- data/opal/corelib/string.rb +86 -52
- data/opal/corelib/string/encoding.rb +140 -25
- data/opal/corelib/string/unpack.rb +26 -40
- data/opal/opal.rb +1 -0
- data/opal/opal/full.rb +1 -0
- data/spec/filters/bugs/array.rb +0 -22
- data/spec/filters/bugs/basicobject.rb +3 -0
- data/spec/filters/bugs/encoding.rb +0 -2
- data/spec/filters/bugs/exception.rb +1 -0
- data/spec/filters/bugs/float.rb +0 -2
- data/spec/filters/bugs/hash.rb +2 -7
- data/spec/filters/bugs/integer.rb +0 -2
- data/spec/filters/bugs/kernel.rb +16 -3
- data/spec/filters/bugs/language.rb +6 -14
- data/spec/filters/bugs/marshal.rb +1 -3
- data/spec/filters/bugs/module.rb +16 -1
- data/spec/filters/bugs/numeric.rb +4 -12
- data/spec/filters/bugs/objectspace.rb +67 -0
- data/spec/filters/bugs/pack_unpack.rb +0 -9
- data/spec/filters/bugs/pathname.rb +1 -0
- data/spec/filters/bugs/proc.rb +8 -0
- data/spec/filters/bugs/random.rb +3 -6
- data/spec/filters/bugs/range.rb +83 -113
- data/spec/filters/bugs/set.rb +2 -0
- data/spec/filters/bugs/string.rb +31 -70
- data/spec/filters/bugs/struct.rb +2 -0
- data/spec/filters/bugs/time.rb +8 -2
- data/spec/filters/unsupported/float.rb +3 -0
- data/spec/filters/unsupported/freeze.rb +1 -0
- data/spec/filters/unsupported/integer.rb +3 -0
- data/spec/filters/unsupported/refinements.rb +5 -0
- data/spec/filters/unsupported/string.rb +100 -95
- data/spec/filters/unsupported/time.rb +4 -0
- data/spec/lib/compiler_spec.rb +16 -0
- data/spec/lib/rewriters/forward_args_spec.rb +61 -0
- data/spec/lib/rewriters/logical_operator_assignment_spec.rb +1 -1
- data/spec/lib/rewriters/numblocks_spec.rb +44 -0
- data/spec/lib/rewriters/opal_engine_check_spec.rb +49 -4
- data/spec/opal/core/language/forward_args_spec.rb +53 -0
- data/spec/opal/core/language/infinite_range_spec.rb +13 -0
- data/spec/opal/core/language/memoization_spec.rb +16 -0
- data/spec/opal/core/module_spec.rb +38 -2
- data/spec/opal/core/number/to_i_spec.rb +28 -0
- data/spec/opal/core/runtime/bridged_classes_spec.rb +16 -0
- data/spec/opal/core/runtime/constants_spec.rb +20 -1
- data/spec/opal/core/string/subclassing_spec.rb +16 -0
- data/spec/opal/core/string/unpack_spec.rb +22 -0
- data/spec/opal/core/string_spec.rb +4 -4
- data/spec/ruby_specs +4 -1
- data/stdlib/json.rb +3 -1
- data/stdlib/securerandom.rb +55 -35
- data/tasks/testing.rake +6 -3
- data/test/nodejs/test_string.rb +25 -0
- data/vendored-minitest/minitest/assertions.rb +2 -0
- metadata +31 -10
- data/lib/opal/parser/with_c_lexer.rb +0 -15
data/opal/corelib/range.rb
CHANGED
|
@@ -9,7 +9,7 @@ class Range
|
|
|
9
9
|
|
|
10
10
|
def initialize(first, last, exclude = false)
|
|
11
11
|
raise NameError, "'initialize' called twice" if @begin
|
|
12
|
-
raise ArgumentError, 'bad value for range' unless first <=> last
|
|
12
|
+
raise ArgumentError, 'bad value for range' unless first <=> last || first.nil? || last.nil?
|
|
13
13
|
|
|
14
14
|
@begin = first
|
|
15
15
|
@end = last
|
|
@@ -20,15 +20,35 @@ class Range
|
|
|
20
20
|
include? value
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
+
%x{
|
|
24
|
+
function is_infinite(self) {
|
|
25
|
+
if (self.begin === nil || self.end === nil ||
|
|
26
|
+
self.begin === -Infinity || self.end === Infinity ||
|
|
27
|
+
self.begin === Infinity || self.end === -Infinity) return true;
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
def count(&block)
|
|
33
|
+
if !block_given? && `is_infinite(self)`
|
|
34
|
+
return Float::INFINITY
|
|
35
|
+
end
|
|
36
|
+
super
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def to_a
|
|
40
|
+
raise TypeError, 'cannot convert endless range to an array' if `is_infinite(self)`
|
|
41
|
+
super
|
|
42
|
+
end
|
|
43
|
+
|
|
23
44
|
def cover?(value)
|
|
24
|
-
beg_cmp = (@begin <=> value)
|
|
25
|
-
|
|
26
|
-
end_cmp = (value <=> @end)
|
|
45
|
+
beg_cmp = (@begin.nil? && -1) || (@begin <=> value) || false
|
|
46
|
+
end_cmp = (@end.nil? && -1) || (value <=> @end) || false
|
|
27
47
|
if @excl
|
|
28
48
|
end_cmp && end_cmp < 0
|
|
29
49
|
else
|
|
30
50
|
end_cmp && end_cmp <= 0
|
|
31
|
-
end
|
|
51
|
+
end && beg_cmp && beg_cmp <= 0
|
|
32
52
|
end
|
|
33
53
|
|
|
34
54
|
def each(&block)
|
|
@@ -62,7 +82,7 @@ class Range
|
|
|
62
82
|
raise TypeError, "can't iterate from #{current.class}"
|
|
63
83
|
end
|
|
64
84
|
|
|
65
|
-
while (current <=> last) < 0
|
|
85
|
+
while @end.nil? || (current <=> last) < 0
|
|
66
86
|
yield current
|
|
67
87
|
|
|
68
88
|
current = current.succ
|
|
@@ -88,6 +108,7 @@ class Range
|
|
|
88
108
|
end
|
|
89
109
|
|
|
90
110
|
def first(n = undefined)
|
|
111
|
+
raise RangeError, 'cannot get the minimum of beginless range' if @begin.nil?
|
|
91
112
|
return @begin if `n == null`
|
|
92
113
|
super
|
|
93
114
|
end
|
|
@@ -95,17 +116,19 @@ class Range
|
|
|
95
116
|
alias include? cover?
|
|
96
117
|
|
|
97
118
|
def last(n = undefined)
|
|
119
|
+
raise RangeError, 'cannot get the maximum of endless range' if @end.nil?
|
|
98
120
|
return @end if `n == null`
|
|
99
121
|
to_a.last(n)
|
|
100
122
|
end
|
|
101
123
|
|
|
102
124
|
# FIXME: currently hardcoded to assume range holds numerics
|
|
103
125
|
def max
|
|
104
|
-
if
|
|
126
|
+
if @end.nil?
|
|
127
|
+
raise RangeError, 'cannot get the maximum of endless range'
|
|
128
|
+
elsif block_given?
|
|
105
129
|
super
|
|
106
|
-
elsif @begin > @end
|
|
107
|
-
|
|
108
|
-
elsif @excl && @begin == @end
|
|
130
|
+
elsif !@begin.nil? && (@begin > @end ||
|
|
131
|
+
@excl && @begin == @end)
|
|
109
132
|
nil
|
|
110
133
|
else
|
|
111
134
|
`#{@excl} ? #{@end} - 1 : #{@end}`
|
|
@@ -115,11 +138,12 @@ class Range
|
|
|
115
138
|
alias member? cover?
|
|
116
139
|
|
|
117
140
|
def min
|
|
118
|
-
if
|
|
141
|
+
if @begin.nil?
|
|
142
|
+
raise RangeError, 'cannot get the minimum of beginless range'
|
|
143
|
+
elsif block_given?
|
|
119
144
|
super
|
|
120
|
-
elsif @begin > @end
|
|
121
|
-
|
|
122
|
-
elsif @excl && @begin == @end
|
|
145
|
+
elsif !@end.nil? && (@begin > @end ||
|
|
146
|
+
@excl && @begin == @end)
|
|
123
147
|
nil
|
|
124
148
|
else
|
|
125
149
|
@begin
|
|
@@ -127,14 +151,17 @@ class Range
|
|
|
127
151
|
end
|
|
128
152
|
|
|
129
153
|
def size
|
|
154
|
+
infinity = Float::INFINITY
|
|
155
|
+
|
|
156
|
+
return 0 if (@begin == infinity && !@end.nil?) || (@end == -infinity && !@begin.nil?)
|
|
157
|
+
return infinity if `is_infinite(self)`
|
|
158
|
+
return nil unless Numeric === @begin && Numeric === @end
|
|
159
|
+
|
|
130
160
|
range_begin = @begin
|
|
131
161
|
range_end = @end
|
|
132
162
|
range_end -= 1 if @excl
|
|
133
163
|
|
|
134
|
-
return nil unless Numeric === range_begin && Numeric === range_end
|
|
135
164
|
return 0 if range_end < range_begin
|
|
136
|
-
infinity = Float::INFINITY
|
|
137
|
-
return infinity if [range_begin.abs, range_end.abs].include?(infinity)
|
|
138
165
|
|
|
139
166
|
`Math.abs(range_end - range_begin) + 1`.to_i
|
|
140
167
|
end
|
|
@@ -228,6 +255,10 @@ class Range
|
|
|
228
255
|
def bsearch(&block)
|
|
229
256
|
return enum_for(:bsearch) unless block_given?
|
|
230
257
|
|
|
258
|
+
if `is_infinite(self) && (self.begin.$$is_number || self.end.$$is_number)`
|
|
259
|
+
raise NotImplementedError, "Can't #bsearch an infinite range"
|
|
260
|
+
end
|
|
261
|
+
|
|
231
262
|
unless `self.begin.$$is_number && self.end.$$is_number`
|
|
232
263
|
raise TypeError, "can't do binary search for #{@begin.class}"
|
|
233
264
|
end
|
|
@@ -236,11 +267,11 @@ class Range
|
|
|
236
267
|
end
|
|
237
268
|
|
|
238
269
|
def to_s
|
|
239
|
-
"#{@begin}#{@excl ? '...' : '..'}#{@end}"
|
|
270
|
+
"#{@begin || ''}#{@excl ? '...' : '..'}#{@end || ''}"
|
|
240
271
|
end
|
|
241
272
|
|
|
242
273
|
def inspect
|
|
243
|
-
"#{@begin.inspect}#{@excl ? '...' : '..'}#{@end.inspect}"
|
|
274
|
+
"#{@begin && @begin.inspect}#{@excl ? '...' : '..'}#{@end && @end.inspect}"
|
|
244
275
|
end
|
|
245
276
|
|
|
246
277
|
def marshal_load(args)
|
data/opal/corelib/runtime.js
CHANGED
|
@@ -533,7 +533,7 @@
|
|
|
533
533
|
Opal.klass = function(scope, superclass, name) {
|
|
534
534
|
var bridged;
|
|
535
535
|
|
|
536
|
-
if (scope == null) {
|
|
536
|
+
if (scope == null || scope == '::') {
|
|
537
537
|
// Global scope
|
|
538
538
|
scope = _Object;
|
|
539
539
|
} else if (!scope.$$is_class && !scope.$$is_module) {
|
|
@@ -542,9 +542,20 @@
|
|
|
542
542
|
}
|
|
543
543
|
|
|
544
544
|
// If the superclass is not an Opal-generated class then we're bridging a native JS class
|
|
545
|
-
if (
|
|
546
|
-
|
|
547
|
-
|
|
545
|
+
if (
|
|
546
|
+
superclass != null && (!superclass.hasOwnProperty || (
|
|
547
|
+
superclass.hasOwnProperty && !superclass.hasOwnProperty('$$is_class')
|
|
548
|
+
))
|
|
549
|
+
) {
|
|
550
|
+
if (superclass.constructor && superclass.constructor.name == "Function") {
|
|
551
|
+
bridged = superclass;
|
|
552
|
+
superclass = _Object;
|
|
553
|
+
} else {
|
|
554
|
+
throw Opal.TypeError.$new("superclass must be a Class (" + (
|
|
555
|
+
(superclass.constructor && (superclass.constructor.name || superclass.constructor.$$name)) ||
|
|
556
|
+
typeof(superclass)
|
|
557
|
+
) + " given)");
|
|
558
|
+
}
|
|
548
559
|
}
|
|
549
560
|
|
|
550
561
|
var klass = find_existing_class(scope, name);
|
|
@@ -643,7 +654,7 @@
|
|
|
643
654
|
Opal.module = function(scope, name) {
|
|
644
655
|
var module;
|
|
645
656
|
|
|
646
|
-
if (scope == null) {
|
|
657
|
+
if (scope == null || scope == '::') {
|
|
647
658
|
// Global scope
|
|
648
659
|
scope = _Object;
|
|
649
660
|
} else if (!scope.$$is_class && !scope.$$is_module) {
|
|
@@ -884,6 +895,31 @@
|
|
|
884
895
|
return value;
|
|
885
896
|
};
|
|
886
897
|
|
|
898
|
+
// Gets class variable with specified +name+ from provided +module+
|
|
899
|
+
//
|
|
900
|
+
// @param module [Module]
|
|
901
|
+
// @param name [String]
|
|
902
|
+
Opal.class_variable_get = function(module, name, tolerant) {
|
|
903
|
+
if ($has_own.call(module.$$cvars, name))
|
|
904
|
+
return module.$$cvars[name];
|
|
905
|
+
|
|
906
|
+
var ancestors = Opal.ancestors(module),
|
|
907
|
+
i, length = ancestors.length;
|
|
908
|
+
|
|
909
|
+
for (i = 0; i < length; i++) {
|
|
910
|
+
var ancestor = ancestors[i];
|
|
911
|
+
|
|
912
|
+
if ($has_own.call(ancestor.$$cvars, name)) {
|
|
913
|
+
return ancestor.$$cvars[name];
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
if (!tolerant)
|
|
918
|
+
throw Opal.NameError.$new('uninitialized class variable '+name+' in '+module.$name());
|
|
919
|
+
|
|
920
|
+
return nil;
|
|
921
|
+
}
|
|
922
|
+
|
|
887
923
|
function isRoot(proto) {
|
|
888
924
|
return proto.hasOwnProperty('$$iclass') && proto.hasOwnProperty('$$root');
|
|
889
925
|
}
|
|
@@ -997,10 +1033,10 @@
|
|
|
997
1033
|
// because there are no intermediate classes between `parent` and `next ancestor`.
|
|
998
1034
|
// It doesn't break any prototypes of other objects as we don't change class references.
|
|
999
1035
|
|
|
1000
|
-
var
|
|
1036
|
+
var parent = includer.$$prototype, module_iclass = Object.getPrototypeOf(parent);
|
|
1001
1037
|
|
|
1002
1038
|
while (module_iclass != null) {
|
|
1003
|
-
if (
|
|
1039
|
+
if (module_iclass.$$module === module && isRoot(module_iclass)) {
|
|
1004
1040
|
break;
|
|
1005
1041
|
}
|
|
1006
1042
|
|
|
@@ -1008,15 +1044,23 @@
|
|
|
1008
1044
|
module_iclass = Object.getPrototypeOf(module_iclass);
|
|
1009
1045
|
}
|
|
1010
1046
|
|
|
1011
|
-
|
|
1047
|
+
if (module_iclass) {
|
|
1048
|
+
// module has been directly included
|
|
1049
|
+
var next_ancestor = Object.getPrototypeOf(module_iclass);
|
|
1012
1050
|
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1051
|
+
// skip non-root iclasses (that were recursively included)
|
|
1052
|
+
while (next_ancestor.hasOwnProperty('$$iclass') && !isRoot(next_ancestor)) {
|
|
1053
|
+
next_ancestor = Object.getPrototypeOf(next_ancestor);
|
|
1054
|
+
}
|
|
1017
1055
|
|
|
1018
|
-
|
|
1019
|
-
|
|
1056
|
+
start_chain_after = parent;
|
|
1057
|
+
end_chain_on = next_ancestor;
|
|
1058
|
+
} else {
|
|
1059
|
+
// module has not been directly included but was in ancestor chain because it was included by another module
|
|
1060
|
+
// include it directly
|
|
1061
|
+
start_chain_after = includer.$$prototype;
|
|
1062
|
+
end_chain_on = Object.getPrototypeOf(includer.$$prototype);
|
|
1063
|
+
}
|
|
1020
1064
|
}
|
|
1021
1065
|
|
|
1022
1066
|
$set_proto(start_chain_after, chain.first);
|
|
@@ -2439,29 +2483,46 @@
|
|
|
2439
2483
|
|
|
2440
2484
|
// Sets the encoding on a string, will treat string literals as frozen strings
|
|
2441
2485
|
// raising a FrozenError.
|
|
2442
|
-
//
|
|
2486
|
+
//
|
|
2487
|
+
// @param str [String] the string on which the encoding should be set
|
|
2443
2488
|
// @param name [String] the canonical name of the encoding
|
|
2444
|
-
|
|
2445
|
-
|
|
2489
|
+
// @param type [String] possible values are either `"encoding"`, `"internal_encoding"`, or `undefined
|
|
2490
|
+
Opal.set_encoding = function(str, name, type) {
|
|
2491
|
+
if (typeof type === "undefined") type = "encoding";
|
|
2492
|
+
if (typeof str === 'string' || str.$$frozen === true)
|
|
2446
2493
|
throw Opal.FrozenError.$new("can't modify frozen String");
|
|
2447
2494
|
|
|
2448
|
-
var encoding = Opal.
|
|
2495
|
+
var encoding = Opal.find_encoding(name);
|
|
2449
2496
|
|
|
2450
|
-
if (encoding === str
|
|
2497
|
+
if (encoding === str[type]) { return str; }
|
|
2451
2498
|
|
|
2452
|
-
str
|
|
2499
|
+
str[type] = encoding;
|
|
2453
2500
|
|
|
2454
2501
|
return str;
|
|
2455
2502
|
};
|
|
2456
2503
|
|
|
2504
|
+
// Fetches the encoding for the given name or raises ArgumentError.
|
|
2505
|
+
Opal.find_encoding = function(name) {
|
|
2506
|
+
var register = Opal.encodings;
|
|
2507
|
+
var encoding = register[name] || register[name.toUpperCase()];
|
|
2508
|
+
if (!encoding) throw Opal.ArgumentError.$new("unknown encoding name - " + name);
|
|
2509
|
+
return encoding;
|
|
2510
|
+
}
|
|
2511
|
+
|
|
2457
2512
|
// @returns a String object with the encoding set from a string literal
|
|
2458
2513
|
Opal.enc = function(str, name) {
|
|
2459
2514
|
var dup = new String(str);
|
|
2460
|
-
Opal.set_encoding(dup, name);
|
|
2515
|
+
dup = Opal.set_encoding(dup, name);
|
|
2461
2516
|
dup.internal_encoding = dup.encoding;
|
|
2462
2517
|
return dup
|
|
2463
2518
|
}
|
|
2464
2519
|
|
|
2520
|
+
// @returns a String object with the internal encoding set to Binary
|
|
2521
|
+
Opal.binary = function(str) {
|
|
2522
|
+
var dup = new String(str);
|
|
2523
|
+
return Opal.set_encoding(dup, "binary", "internal_encoding");
|
|
2524
|
+
}
|
|
2525
|
+
|
|
2465
2526
|
|
|
2466
2527
|
// Initialization
|
|
2467
2528
|
// --------------
|
data/opal/corelib/string.rb
CHANGED
|
@@ -29,18 +29,26 @@ class String < `String`
|
|
|
29
29
|
Opal.coerce_to?(what, String, :to_str)
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
def self.new(
|
|
33
|
-
str = `$coerce_to(str, #{String}, 'to_str')`
|
|
34
|
-
`new self.$$constructor(str)`
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def initialize(str = undefined)
|
|
32
|
+
def self.new(*args)
|
|
38
33
|
%x{
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
34
|
+
var str = args[0] || "";
|
|
35
|
+
var opts = args[args.length-1];
|
|
36
|
+
str = $coerce_to(str, #{String}, 'to_str');
|
|
37
|
+
if (opts && opts.$$is_hash) {
|
|
38
|
+
if (opts.$$smap.encoding) str = str.$force_encoding(opts.$$smap.encoding);
|
|
39
|
+
}
|
|
40
|
+
str = new self.$$constructor(str);
|
|
41
|
+
if (!str.$initialize.$$pristine) #{`str`.initialize(*args)};
|
|
42
|
+
return str;
|
|
42
43
|
}
|
|
43
|
-
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Our initialize method does nothing, the string value setup is being
|
|
47
|
+
# done by String.new. Therefore not all kinds of subclassing will work.
|
|
48
|
+
# As a rule of thumb, when subclassing String, either make sure to override
|
|
49
|
+
# .new or make sure that the first argument given to a constructor is
|
|
50
|
+
# a string we want our subclass-string to hold.
|
|
51
|
+
def initialize(str = undefined, encoding: nil, capacity: nil)
|
|
44
52
|
end
|
|
45
53
|
|
|
46
54
|
def %(data)
|
|
@@ -92,7 +100,14 @@ class String < `String`
|
|
|
92
100
|
def +(other)
|
|
93
101
|
other = `$coerce_to(#{other}, #{String}, 'to_str')`
|
|
94
102
|
|
|
95
|
-
|
|
103
|
+
%x{
|
|
104
|
+
if (other == "" && self.$$class === Opal.String) return #{self};
|
|
105
|
+
if (self == "" && other.$$class === Opal.String) return #{other};
|
|
106
|
+
var out = self + other;
|
|
107
|
+
if (self.encoding === out.encoding && other.encoding === out.encoding) return out;
|
|
108
|
+
if (self.encoding.name === "UTF-8" || other.encoding.name === "UTF-8") return out;
|
|
109
|
+
return Opal.enc(out, self.encoding);
|
|
110
|
+
}
|
|
96
111
|
end
|
|
97
112
|
|
|
98
113
|
def <=>(other)
|
|
@@ -240,7 +255,7 @@ class String < `String`
|
|
|
240
255
|
alias byteslice []
|
|
241
256
|
|
|
242
257
|
def b
|
|
243
|
-
force_encoding('binary')
|
|
258
|
+
`new String(#{self})`.force_encoding('binary')
|
|
244
259
|
end
|
|
245
260
|
|
|
246
261
|
def capitalize
|
|
@@ -289,12 +304,6 @@ class String < `String`
|
|
|
289
304
|
}
|
|
290
305
|
end
|
|
291
306
|
|
|
292
|
-
def chars(&block)
|
|
293
|
-
return each_char.to_a unless block
|
|
294
|
-
|
|
295
|
-
each_char(&block)
|
|
296
|
-
end
|
|
297
|
-
|
|
298
307
|
def chomp(separator = $/)
|
|
299
308
|
return self if `separator === nil || self.length === 0`
|
|
300
309
|
|
|
@@ -416,18 +425,6 @@ class String < `String`
|
|
|
416
425
|
`self.$$cast(self.toLowerCase())`
|
|
417
426
|
end
|
|
418
427
|
|
|
419
|
-
def each_char(&block)
|
|
420
|
-
return enum_for(:each_char) { size } unless block_given?
|
|
421
|
-
|
|
422
|
-
%x{
|
|
423
|
-
for (var i = 0, length = self.length; i < length; i++) {
|
|
424
|
-
Opal.yield1(block, self.charAt(i));
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
self
|
|
429
|
-
end
|
|
430
|
-
|
|
431
428
|
def each_line(separator = $/, &block)
|
|
432
429
|
return enum_for :each_line, separator unless block_given?
|
|
433
430
|
|
|
@@ -645,7 +642,13 @@ class String < `String`
|
|
|
645
642
|
'\\': '\\\\'
|
|
646
643
|
},
|
|
647
644
|
escaped = self.replace(escapable, function (chr) {
|
|
648
|
-
|
|
645
|
+
if (meta[chr]) return meta[chr];
|
|
646
|
+
chr = chr.charCodeAt(0);
|
|
647
|
+
if (chr <= 0xff && (self.encoding["$binary?"]() || self.internal_encoding["$binary?"]())) {
|
|
648
|
+
return '\\x' + ('00' + chr.toString(16).toUpperCase()).slice(-2);
|
|
649
|
+
} else {
|
|
650
|
+
return '\\u' + ('0000' + chr.toString(16).toUpperCase()).slice(-4);
|
|
651
|
+
}
|
|
649
652
|
});
|
|
650
653
|
return '"' + escaped.replace(/\#[\$\@\{]/g, '\\$&') + '"';
|
|
651
654
|
}
|
|
@@ -660,10 +663,6 @@ class String < `String`
|
|
|
660
663
|
block ? self : e.to_a
|
|
661
664
|
end
|
|
662
665
|
|
|
663
|
-
def length
|
|
664
|
-
`self.length`
|
|
665
|
-
end
|
|
666
|
-
|
|
667
666
|
def ljust(width, padstr = ' ')
|
|
668
667
|
width = `$coerce_to(#{width}, #{Integer}, 'to_int')`
|
|
669
668
|
padstr = `$coerce_to(#{padstr}, #{String}, 'to_str')`.to_s
|
|
@@ -694,17 +693,10 @@ class String < `String`
|
|
|
694
693
|
|
|
695
694
|
def ascii_only?
|
|
696
695
|
# non-ASCII-compatible encoding must return false
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
# - "hello".force_encoding("UTF-16LE")
|
|
702
|
-
# - "hello"
|
|
703
|
-
# The problem is that "ascii_only" should return false in the first case and true in the second case.
|
|
704
|
-
if encoding == Encoding::UTF_16BE
|
|
705
|
-
return false
|
|
706
|
-
end
|
|
707
|
-
`/^[\x00-\x7F]*$/.test(self)`
|
|
696
|
+
%x{
|
|
697
|
+
if (!self.encoding.ascii) return false;
|
|
698
|
+
return /^[\x00-\x7F]*$/.test(self);
|
|
699
|
+
}
|
|
708
700
|
end
|
|
709
701
|
|
|
710
702
|
def match(pattern, pos = undefined, &block)
|
|
@@ -845,7 +837,14 @@ class String < `String`
|
|
|
845
837
|
end
|
|
846
838
|
|
|
847
839
|
def ord
|
|
848
|
-
|
|
840
|
+
%x{
|
|
841
|
+
if (typeof self.codePointAt === "function") {
|
|
842
|
+
return self.codePointAt(0);
|
|
843
|
+
}
|
|
844
|
+
else {
|
|
845
|
+
return self.charCodeAt(0);
|
|
846
|
+
}
|
|
847
|
+
}
|
|
849
848
|
end
|
|
850
849
|
|
|
851
850
|
def partition(sep)
|
|
@@ -1022,8 +1021,6 @@ class String < `String`
|
|
|
1022
1021
|
}
|
|
1023
1022
|
end
|
|
1024
1023
|
|
|
1025
|
-
alias size length
|
|
1026
|
-
|
|
1027
1024
|
alias slice []
|
|
1028
1025
|
|
|
1029
1026
|
def split(pattern = undefined, limit = undefined)
|
|
@@ -1141,10 +1138,22 @@ class String < `String`
|
|
|
1141
1138
|
def start_with?(*prefixes)
|
|
1142
1139
|
%x{
|
|
1143
1140
|
for (var i = 0, length = prefixes.length; i < length; i++) {
|
|
1144
|
-
|
|
1141
|
+
if (prefixes[i].$$is_regexp) {
|
|
1142
|
+
var regexp = prefixes[i];
|
|
1143
|
+
var match = regexp.exec(self);
|
|
1145
1144
|
|
|
1146
|
-
|
|
1147
|
-
|
|
1145
|
+
if (match != null && match.index === 0) {
|
|
1146
|
+
#{$~ = MatchData.new(`regexp`, `match`)};
|
|
1147
|
+
return true;
|
|
1148
|
+
} else {
|
|
1149
|
+
#{$~ = nil}
|
|
1150
|
+
}
|
|
1151
|
+
} else {
|
|
1152
|
+
var prefix = $coerce_to(prefixes[i], #{String}, 'to_str').$to_s();
|
|
1153
|
+
|
|
1154
|
+
if (self.indexOf(prefix) === 0) {
|
|
1155
|
+
return true;
|
|
1156
|
+
}
|
|
1148
1157
|
}
|
|
1149
1158
|
}
|
|
1150
1159
|
|
|
@@ -1841,6 +1850,31 @@ class String < `String`
|
|
|
1841
1850
|
def unpack1(format)
|
|
1842
1851
|
raise "To use String#unpack1, you must first require 'corelib/string/unpack'."
|
|
1843
1852
|
end
|
|
1853
|
+
|
|
1854
|
+
def freeze
|
|
1855
|
+
%x{
|
|
1856
|
+
if (typeof self === 'string') return self;
|
|
1857
|
+
self.$$frozen = true;
|
|
1858
|
+
return self;
|
|
1859
|
+
}
|
|
1860
|
+
end
|
|
1861
|
+
|
|
1862
|
+
alias +@ dup
|
|
1863
|
+
|
|
1864
|
+
def -@
|
|
1865
|
+
%x{
|
|
1866
|
+
if (typeof self === 'string') return self;
|
|
1867
|
+
if (self.$$frozen === true) return self;
|
|
1868
|
+
if (self.encoding.name == 'UTF-8' && self.internal_encoding.name == 'UTF-8') return self.toString();
|
|
1869
|
+
return self.$dup().$freeze();
|
|
1870
|
+
}
|
|
1871
|
+
end
|
|
1872
|
+
|
|
1873
|
+
def frozen?
|
|
1874
|
+
`typeof self === 'string' || self.$$frozen === true`
|
|
1875
|
+
end
|
|
1876
|
+
|
|
1877
|
+
Opal.pristine self, :initialize
|
|
1844
1878
|
end
|
|
1845
1879
|
|
|
1846
1880
|
Symbol = String
|