opal 1.1.0.rc1 → 1.2.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +4 -4
- 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/CHANGELOG.md +42 -1
- data/Gemfile +0 -4
- data/HACKING.md +1 -1
- data/LICENSE +1 -1
- data/README.md +20 -16
- data/UNRELEASED.md +32 -95
- data/benchmark-ips/bm_array_unshift.rb +7 -0
- data/benchmark-ips/bm_js_symbols_vs_strings.rb +7 -2
- data/bin/build-browser-source-map-support +2 -3
- 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 +5 -1
- data/lib/opal/cli_runners/source-map-support-browser.js +8 -2
- data/lib/opal/cli_runners/source-map-support-node.js +3706 -0
- 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.gemspec +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/package.json +1 -1
- 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 +35 -12
- 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
|