homura-runtime 0.3.6 → 0.3.8
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/CHANGELOG.md +20 -0
- data/exe/auto-await +42 -27
- data/exe/compile-assets +46 -37
- data/exe/compile-erb +86 -61
- data/exe/homura-build +223 -119
- data/lib/homura/runtime/ai.rb +316 -22
- data/lib/homura/runtime/async_registry.rb +135 -98
- data/lib/homura/runtime/auto_await/analyzer.rb +34 -19
- data/lib/homura/runtime/auto_await/transformer.rb +1 -1
- data/lib/homura/runtime/build_support.rb +74 -38
- data/lib/homura/runtime/cache.rb +29 -22
- data/lib/homura/runtime/durable_object.rb +110 -56
- data/lib/homura/runtime/email.rb +28 -14
- data/lib/homura/runtime/http.rb +5 -4
- data/lib/homura/runtime/multipart.rb +47 -47
- data/lib/homura/runtime/queue.rb +82 -29
- data/lib/homura/runtime/scheduled.rb +29 -19
- data/lib/homura/runtime/stream.rb +30 -24
- data/lib/homura/runtime/version.rb +1 -1
- data/lib/homura/runtime.rb +351 -131
- data/lib/homura_vendor_tempfile.rb +5 -4
- data/lib/homura_vendor_tilt.rb +4 -3
- data/lib/homura_vendor_zlib.rb +20 -13
- data/lib/opal_patches.rb +196 -109
- metadata +1 -1
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "stringio"
|
|
4
4
|
|
|
5
5
|
class Tempfile < StringIO
|
|
6
6
|
def initialize(*)
|
|
7
|
-
super(
|
|
7
|
+
super("")
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
def self.open(*)
|
|
11
|
-
raise NotImplementedError,
|
|
11
|
+
raise NotImplementedError,
|
|
12
|
+
"Tempfile is stubbed in homura (Workers have no writable FS)"
|
|
12
13
|
end
|
|
13
14
|
|
|
14
15
|
def path
|
|
15
|
-
raise NotImplementedError,
|
|
16
|
+
raise NotImplementedError, "Tempfile#path stubbed (no FS)"
|
|
16
17
|
end
|
|
17
18
|
|
|
18
19
|
def unlink
|
data/lib/homura_vendor_tilt.rb
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Tilt
|
|
4
|
-
class TemplateNotFound < StandardError
|
|
4
|
+
class TemplateNotFound < StandardError
|
|
5
|
+
end
|
|
5
6
|
|
|
6
7
|
class Cache
|
|
7
8
|
def initialize
|
|
@@ -56,8 +57,8 @@ module Tilt
|
|
|
56
57
|
|
|
57
58
|
def new(file = nil, line = nil, options = {}, &block)
|
|
58
59
|
raise NotImplementedError,
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
"Tilt template rendering is not available in homura Phase 2 " \
|
|
61
|
+
"(stubbed). Return Strings or arrays from your Sinatra handlers."
|
|
61
62
|
end
|
|
62
63
|
end
|
|
63
64
|
end
|
data/lib/homura_vendor_zlib.rb
CHANGED
|
@@ -1,48 +1,55 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Zlib
|
|
4
|
-
class Error < StandardError
|
|
4
|
+
class Error < StandardError
|
|
5
|
+
end
|
|
5
6
|
|
|
6
7
|
class GzipFile
|
|
7
|
-
class Error < Zlib::Error
|
|
8
|
-
|
|
9
|
-
class
|
|
10
|
-
|
|
8
|
+
class Error < Zlib::Error
|
|
9
|
+
end
|
|
10
|
+
class CRCError < Error
|
|
11
|
+
end
|
|
12
|
+
class LengthError < Error
|
|
13
|
+
end
|
|
14
|
+
class NoFooter < Error
|
|
15
|
+
end
|
|
11
16
|
end
|
|
12
17
|
|
|
13
18
|
class GzipReader < GzipFile
|
|
14
19
|
def self.wrap(*)
|
|
15
|
-
raise NotImplementedError,
|
|
20
|
+
raise NotImplementedError, "Zlib stubbed"
|
|
16
21
|
end
|
|
17
22
|
end
|
|
18
23
|
|
|
19
24
|
class GzipWriter < GzipFile
|
|
20
25
|
def self.wrap(*)
|
|
21
|
-
raise NotImplementedError,
|
|
26
|
+
raise NotImplementedError, "Zlib stubbed"
|
|
22
27
|
end
|
|
23
28
|
end
|
|
24
29
|
|
|
25
30
|
class Deflate
|
|
26
31
|
def self.deflate(*)
|
|
27
|
-
raise NotImplementedError,
|
|
32
|
+
raise NotImplementedError, "Zlib stubbed"
|
|
28
33
|
end
|
|
29
34
|
|
|
30
|
-
def initialize(*)
|
|
35
|
+
def initialize(*)
|
|
36
|
+
end
|
|
31
37
|
|
|
32
38
|
def deflate(*)
|
|
33
|
-
raise NotImplementedError,
|
|
39
|
+
raise NotImplementedError, "Zlib stubbed"
|
|
34
40
|
end
|
|
35
41
|
|
|
36
42
|
def finish
|
|
37
|
-
raise NotImplementedError,
|
|
43
|
+
raise NotImplementedError, "Zlib stubbed"
|
|
38
44
|
end
|
|
39
45
|
|
|
40
|
-
def close
|
|
46
|
+
def close
|
|
47
|
+
end
|
|
41
48
|
end
|
|
42
49
|
|
|
43
50
|
class Inflate
|
|
44
51
|
def self.inflate(*)
|
|
45
|
-
raise NotImplementedError,
|
|
52
|
+
raise NotImplementedError, "Zlib stubbed"
|
|
46
53
|
end
|
|
47
54
|
end
|
|
48
55
|
|
data/lib/opal_patches.rb
CHANGED
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
# approximate here as a no-op (Opal has no const-access hook to warn
|
|
25
25
|
# from, and a warning-only behaviour does not affect program output).
|
|
26
26
|
class Module
|
|
27
|
-
unless private_method_defined?(:deprecate_constant) ||
|
|
27
|
+
unless private_method_defined?(:deprecate_constant) ||
|
|
28
|
+
method_defined?(:deprecate_constant)
|
|
28
29
|
def deprecate_constant(*_names)
|
|
29
30
|
self
|
|
30
31
|
end
|
|
@@ -69,9 +70,9 @@ class Module
|
|
|
69
70
|
|
|
70
71
|
def const_defined?(name, inherit = true)
|
|
71
72
|
name_str = name.to_s
|
|
72
|
-
if name_str.include?(
|
|
73
|
-
parts = name_str.split(
|
|
74
|
-
parts.shift if parts.first.empty?
|
|
73
|
+
if name_str.include?("::")
|
|
74
|
+
parts = name_str.split("::")
|
|
75
|
+
parts.shift if parts.first.empty? # leading "::Foo::Bar"
|
|
75
76
|
current = self
|
|
76
77
|
parts.each do |part|
|
|
77
78
|
return false unless current.__homura_const_defined_simple(part, inherit)
|
|
@@ -92,7 +93,7 @@ end
|
|
|
92
93
|
# as nil, which breaks gems that call `File.expand_path($0)` at class-
|
|
93
94
|
# body time (sinatra/main.rb: `proc { File.expand_path($0) }`).
|
|
94
95
|
# Install a harmless default string.
|
|
95
|
-
$0 ||=
|
|
96
|
+
$0 ||= "(homura)"
|
|
96
97
|
$PROGRAM_NAME ||= $0
|
|
97
98
|
|
|
98
99
|
# (Previously this file force-set APP_ENV/RACK_ENV to 'production' to
|
|
@@ -106,7 +107,7 @@ $PROGRAM_NAME ||= $0
|
|
|
106
107
|
# Load Opal's stdlib Forwardable BEFORE patching it, so our overrides
|
|
107
108
|
# are applied last and are not clobbered when a vendored gem requires
|
|
108
109
|
# 'forwardable' transitively.
|
|
109
|
-
require
|
|
110
|
+
require "forwardable"
|
|
110
111
|
|
|
111
112
|
# -----------------------------------------------------------------
|
|
112
113
|
# (removed) Debug method_missing logger — was used while iterating
|
|
@@ -152,25 +153,30 @@ module ForwardableAccessor
|
|
|
152
153
|
def resolve(instance, expr)
|
|
153
154
|
expr = expr.to_s
|
|
154
155
|
current = instance
|
|
155
|
-
expr
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
156
|
+
expr
|
|
157
|
+
.split(".")
|
|
158
|
+
.each do |part|
|
|
159
|
+
current =
|
|
160
|
+
if part == "self"
|
|
161
|
+
instance
|
|
162
|
+
elsif part.start_with?("@")
|
|
163
|
+
instance.instance_variable_get(part)
|
|
164
|
+
else
|
|
165
|
+
current.__send__(part)
|
|
166
|
+
end
|
|
167
|
+
end
|
|
164
168
|
current
|
|
165
169
|
end
|
|
166
170
|
end
|
|
167
171
|
|
|
168
172
|
module Forwardable
|
|
169
|
-
|
|
173
|
+
if method_defined?(:def_instance_delegator)
|
|
174
|
+
remove_method :def_instance_delegator
|
|
175
|
+
end
|
|
170
176
|
|
|
171
177
|
def def_instance_delegator(accessor, method, ali = method)
|
|
172
178
|
accessor_str = accessor.to_s
|
|
173
|
-
if accessor_str.start_with?(
|
|
179
|
+
if accessor_str.start_with?("@") && !accessor_str.include?(".")
|
|
174
180
|
define_method ali do |*args, &block|
|
|
175
181
|
instance_variable_get(accessor_str).__send__(method, *args, &block)
|
|
176
182
|
end
|
|
@@ -182,7 +188,11 @@ module Forwardable
|
|
|
182
188
|
else
|
|
183
189
|
# Dot-path expression like 'self.class'. Resolve without eval.
|
|
184
190
|
define_method ali do |*args, &block|
|
|
185
|
-
ForwardableAccessor.resolve(self, accessor_str).__send__(
|
|
191
|
+
ForwardableAccessor.resolve(self, accessor_str).__send__(
|
|
192
|
+
method,
|
|
193
|
+
*args,
|
|
194
|
+
&block
|
|
195
|
+
)
|
|
186
196
|
end
|
|
187
197
|
end
|
|
188
198
|
end
|
|
@@ -193,7 +203,7 @@ module SingleForwardable
|
|
|
193
203
|
|
|
194
204
|
def def_single_delegator(accessor, method, ali = method)
|
|
195
205
|
accessor_str = accessor.to_s
|
|
196
|
-
if accessor_str.start_with?(
|
|
206
|
+
if accessor_str.start_with?("@") && !accessor_str.include?(".")
|
|
197
207
|
define_singleton_method ali do |*args, &block|
|
|
198
208
|
instance_variable_get(accessor_str).__send__(method, *args, &block)
|
|
199
209
|
end
|
|
@@ -203,7 +213,11 @@ module SingleForwardable
|
|
|
203
213
|
end
|
|
204
214
|
else
|
|
205
215
|
define_singleton_method ali do |*args, &block|
|
|
206
|
-
ForwardableAccessor.resolve(self, accessor_str).__send__(
|
|
216
|
+
ForwardableAccessor.resolve(self, accessor_str).__send__(
|
|
217
|
+
method,
|
|
218
|
+
*args,
|
|
219
|
+
&block
|
|
220
|
+
)
|
|
207
221
|
end
|
|
208
222
|
end
|
|
209
223
|
end
|
|
@@ -223,26 +237,31 @@ end
|
|
|
223
237
|
# We install a module-shaped URI::DEFAULT_PARSER that wraps CGI so
|
|
224
238
|
# that gems that only call escape / unescape / regexp[:UNSAFE] on it
|
|
225
239
|
# continue to work.
|
|
226
|
-
|
|
227
|
-
require
|
|
240
|
+
begin
|
|
241
|
+
require "uri"
|
|
242
|
+
rescue StandardError
|
|
243
|
+
nil
|
|
244
|
+
end
|
|
245
|
+
require "cgi"
|
|
228
246
|
|
|
229
247
|
module ::URI
|
|
230
248
|
unless const_defined?(:DEFAULT_PARSER)
|
|
231
|
-
DEFAULT_PARSER =
|
|
232
|
-
|
|
249
|
+
DEFAULT_PARSER =
|
|
250
|
+
Module.new do
|
|
251
|
+
UNSAFE = Regexp.compile('[^\-_.!~*\'()a-zA-Z0-9;/?:@&=+$,\[\]]').freeze
|
|
233
252
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
253
|
+
def self.regexp
|
|
254
|
+
{ UNSAFE: UNSAFE }
|
|
255
|
+
end
|
|
237
256
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
257
|
+
def self.escape(s, unsafe = UNSAFE)
|
|
258
|
+
CGI.escape(s.to_s)
|
|
259
|
+
end
|
|
241
260
|
|
|
242
|
-
|
|
243
|
-
|
|
261
|
+
def self.unescape(s)
|
|
262
|
+
CGI.unescape(s.to_s)
|
|
263
|
+
end
|
|
244
264
|
end
|
|
245
|
-
end
|
|
246
265
|
end
|
|
247
266
|
|
|
248
267
|
# CRuby's URI.decode_www_form_component / encode_www_form_component are used
|
|
@@ -256,7 +275,7 @@ module ::URI
|
|
|
256
275
|
# bodies need **decodeURIComponent** semantics (same as CGI.unescapeURIComponent).
|
|
257
276
|
# Without this, HTML like `</h1>` survives as literal `<%2Fh1>` in params.
|
|
258
277
|
def self.decode_www_form_component(str, _enc = nil)
|
|
259
|
-
s = str.to_s.tr(
|
|
278
|
+
s = str.to_s.tr("+", " ")
|
|
260
279
|
CGI.unescapeURIComponent(s)
|
|
261
280
|
rescue ::Exception
|
|
262
281
|
str.to_s
|
|
@@ -268,9 +287,7 @@ module ::URI
|
|
|
268
287
|
end
|
|
269
288
|
end
|
|
270
289
|
|
|
271
|
-
unless const_defined?(:RFC2396_PARSER)
|
|
272
|
-
RFC2396_PARSER = DEFAULT_PARSER
|
|
273
|
-
end
|
|
290
|
+
RFC2396_PARSER = DEFAULT_PARSER unless const_defined?(:RFC2396_PARSER)
|
|
274
291
|
|
|
275
292
|
unless const_defined?(:Parser)
|
|
276
293
|
# Some gems instantiate URI::Parser.new directly. Return the
|
|
@@ -285,11 +302,13 @@ module ::URI
|
|
|
285
302
|
# Rack::Protection::JsonCsrf#has_vector? does `rescue URI::InvalidURIError`,
|
|
286
303
|
# so the constant needs to exist even if the referrer is actually valid.
|
|
287
304
|
unless const_defined?(:InvalidURIError)
|
|
288
|
-
class InvalidURIError < StandardError
|
|
305
|
+
class InvalidURIError < StandardError
|
|
306
|
+
end
|
|
289
307
|
end
|
|
290
308
|
|
|
291
309
|
unless const_defined?(:Error)
|
|
292
|
-
class Error < StandardError
|
|
310
|
+
class Error < StandardError
|
|
311
|
+
end
|
|
293
312
|
end
|
|
294
313
|
|
|
295
314
|
# Opal's stdlib does not implement URI.parse. Rack::Protection calls
|
|
@@ -310,9 +329,21 @@ module ::URI
|
|
|
310
329
|
|
|
311
330
|
def self.parse(str)
|
|
312
331
|
s = str.to_s
|
|
313
|
-
|
|
332
|
+
if s.empty?
|
|
333
|
+
return(
|
|
334
|
+
Generic.new(
|
|
335
|
+
host: nil,
|
|
336
|
+
scheme: nil,
|
|
337
|
+
port: nil,
|
|
338
|
+
path: "",
|
|
339
|
+
query: nil,
|
|
340
|
+
fragment: nil
|
|
341
|
+
)
|
|
342
|
+
)
|
|
343
|
+
end
|
|
314
344
|
|
|
315
|
-
js_url =
|
|
345
|
+
js_url =
|
|
346
|
+
`
|
|
316
347
|
(function() {
|
|
317
348
|
try { return new URL(#{s}); }
|
|
318
349
|
catch (e) {
|
|
@@ -321,24 +352,33 @@ module ::URI
|
|
|
321
352
|
}
|
|
322
353
|
})()
|
|
323
354
|
`
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
scheme
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
query
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
frag
|
|
340
|
-
|
|
341
|
-
|
|
355
|
+
if `#{js_url} == null`
|
|
356
|
+
raise ::URI::InvalidURIError, "bad URI(is not URI?): #{s}"
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
host = `#{js_url}.host` || ""
|
|
360
|
+
host = nil if host == "" || host.include?("__homura.invalid")
|
|
361
|
+
scheme = `#{js_url}.protocol` || ""
|
|
362
|
+
scheme = scheme.sub(/:$/, "")
|
|
363
|
+
scheme = nil if scheme == ""
|
|
364
|
+
port_raw = `#{js_url}.port` || ""
|
|
365
|
+
port = port_raw == "" ? nil : port_raw.to_i
|
|
366
|
+
path = `#{js_url}.pathname` || ""
|
|
367
|
+
query = `#{js_url}.search` || ""
|
|
368
|
+
query = query.sub(/^\?/, "")
|
|
369
|
+
query = nil if query == ""
|
|
370
|
+
frag = `#{js_url}.hash` || ""
|
|
371
|
+
frag = frag.sub(/^#/, "")
|
|
372
|
+
frag = nil if frag == ""
|
|
373
|
+
|
|
374
|
+
Generic.new(
|
|
375
|
+
host: host,
|
|
376
|
+
scheme: scheme,
|
|
377
|
+
port: port,
|
|
378
|
+
path: path,
|
|
379
|
+
query: query,
|
|
380
|
+
fragment: frag
|
|
381
|
+
)
|
|
342
382
|
end
|
|
343
383
|
|
|
344
384
|
# Net::HTTP.get(URI('https://...')) is the canonical entry point in
|
|
@@ -347,7 +387,7 @@ module ::URI
|
|
|
347
387
|
# omits that; install it here so vendored gems (and our Net::HTTP
|
|
348
388
|
# shim) can use the idiomatic short form.
|
|
349
389
|
def self.HTTP_class_for(scheme)
|
|
350
|
-
HTTP if scheme ==
|
|
390
|
+
HTTP if scheme == "http"
|
|
351
391
|
end
|
|
352
392
|
end
|
|
353
393
|
|
|
@@ -400,11 +440,11 @@ end
|
|
|
400
440
|
# `opal_patches` is loaded directly through the plain Opal CLI as well as
|
|
401
441
|
# through `homura build`. Digest itself now lives in opal-homura stdlib;
|
|
402
442
|
# the remaining Workers-specific shims stay local to this gem.
|
|
403
|
-
require
|
|
404
|
-
require
|
|
405
|
-
require
|
|
406
|
-
require
|
|
407
|
-
require
|
|
443
|
+
require "digest"
|
|
444
|
+
require "digest/sha2"
|
|
445
|
+
require "homura_vendor_zlib"
|
|
446
|
+
require "homura_vendor_tempfile"
|
|
447
|
+
require "homura_vendor_tilt"
|
|
408
448
|
|
|
409
449
|
module ::SecureRandom
|
|
410
450
|
# Raised when neither node:crypto.randomBytes nor Web Crypto
|
|
@@ -423,21 +463,28 @@ module ::SecureRandom
|
|
|
423
463
|
# cryptographic randomness; only the module-load case ever falls
|
|
424
464
|
# back, and Sinatra's session secret is the lone caller that
|
|
425
465
|
# actually does that gracefully.
|
|
426
|
-
class EntropyError < ::NotImplementedError
|
|
466
|
+
class EntropyError < ::NotImplementedError
|
|
467
|
+
end
|
|
427
468
|
|
|
428
469
|
def self.random_bytes(n = 16)
|
|
429
470
|
n = n.to_i
|
|
430
471
|
n = 16 if n <= 0
|
|
431
472
|
hex_string = secure_hex_bytes(n)
|
|
432
|
-
|
|
433
|
-
|
|
473
|
+
if hex_string.nil?
|
|
474
|
+
raise EntropyError,
|
|
475
|
+
"no source of cryptographic entropy available (node:crypto AND Web Crypto both unreachable)"
|
|
476
|
+
end
|
|
477
|
+
[hex_string].pack("H*")
|
|
434
478
|
end
|
|
435
479
|
|
|
436
480
|
def self.hex(n = 16)
|
|
437
481
|
n = n.to_i
|
|
438
482
|
n = 16 if n <= 0
|
|
439
483
|
out = secure_hex_bytes(n)
|
|
440
|
-
|
|
484
|
+
if out.nil?
|
|
485
|
+
raise EntropyError,
|
|
486
|
+
"no source of cryptographic entropy available (node:crypto AND Web Crypto both unreachable)"
|
|
487
|
+
end
|
|
441
488
|
out
|
|
442
489
|
end
|
|
443
490
|
|
|
@@ -447,13 +494,13 @@ module ::SecureRandom
|
|
|
447
494
|
end
|
|
448
495
|
|
|
449
496
|
def self.base64(n = 16)
|
|
450
|
-
require
|
|
497
|
+
require "base64"
|
|
451
498
|
Base64.strict_encode64(random_bytes(n))
|
|
452
499
|
end
|
|
453
500
|
|
|
454
501
|
def self.urlsafe_base64(n = 16, padding = false)
|
|
455
|
-
s = base64(n).tr(
|
|
456
|
-
padding ? s : s.delete(
|
|
502
|
+
s = base64(n).tr("+/", "-_")
|
|
503
|
+
padding ? s : s.delete("=")
|
|
457
504
|
end
|
|
458
505
|
|
|
459
506
|
# NOTE: `SecureRandom.random_number` is provided by `Random::Formatter`
|
|
@@ -471,7 +518,8 @@ module ::SecureRandom
|
|
|
471
518
|
def self.secure_hex_bytes(n)
|
|
472
519
|
# Opal does not always auto-return backtick IIFEs; assign first
|
|
473
520
|
# so the method's last expression is a normal Ruby reference.
|
|
474
|
-
result =
|
|
521
|
+
result =
|
|
522
|
+
`(function(n) {
|
|
475
523
|
try {
|
|
476
524
|
if (typeof globalThis.__nodeCrypto__ !== 'undefined' && globalThis.__nodeCrypto__) {
|
|
477
525
|
return globalThis.__nodeCrypto__.randomBytes(n).toString('hex');
|
|
@@ -516,16 +564,19 @@ class ::Array
|
|
|
516
564
|
# this divergence in the initial Phase 7 PR.
|
|
517
565
|
def pack(format)
|
|
518
566
|
fmt = format.to_s
|
|
519
|
-
|
|
567
|
+
unless fmt == "H*" || fmt =~ /\AH(\d+)\z/
|
|
568
|
+
return pack_without_homura_hex(format)
|
|
569
|
+
end
|
|
520
570
|
|
|
521
571
|
hex = self.first.to_s
|
|
522
|
-
nibble_count =
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
572
|
+
nibble_count =
|
|
573
|
+
if fmt == "H*"
|
|
574
|
+
hex.length
|
|
575
|
+
else
|
|
576
|
+
[fmt[1..-1].to_i, hex.length].min
|
|
577
|
+
end
|
|
578
|
+
nibble_count -= 1 if nibble_count.odd? # round down to whole bytes
|
|
579
|
+
out = ""
|
|
529
580
|
i = 0
|
|
530
581
|
while i < nibble_count
|
|
531
582
|
out = out + hex[i, 2].to_i(16).chr
|
|
@@ -553,20 +604,23 @@ class ::String
|
|
|
553
604
|
# `n` nibbles (rounded down to whole bytes for an odd `n`).
|
|
554
605
|
def unpack1(format)
|
|
555
606
|
fmt = format.to_s
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
607
|
+
unless fmt == "H*" || fmt =~ /\AH(\d+)\z/
|
|
608
|
+
return unpack1_without_homura_hex(format)
|
|
609
|
+
end
|
|
610
|
+
|
|
611
|
+
requested_nibbles =
|
|
612
|
+
if fmt == "H*"
|
|
613
|
+
self.length * 2
|
|
614
|
+
else
|
|
615
|
+
fmt[1..-1].to_i
|
|
616
|
+
end
|
|
617
|
+
out = ""
|
|
564
618
|
i = 0
|
|
565
619
|
n = self.length
|
|
566
620
|
while i < n && out.length < requested_nibbles
|
|
567
621
|
b = `(#{self}.charCodeAt(#{i}) & 0xff)`
|
|
568
622
|
h = b.to_s(16)
|
|
569
|
-
h =
|
|
623
|
+
h = "0" + h if h.length == 1
|
|
570
624
|
out = out + h
|
|
571
625
|
i += 1
|
|
572
626
|
end
|
|
@@ -588,7 +642,8 @@ end
|
|
|
588
642
|
# Install the same stubs on File defensively.
|
|
589
643
|
begin
|
|
590
644
|
file_class = ::File
|
|
591
|
-
unless file_class.respond_to?(:read) &&
|
|
645
|
+
unless file_class.respond_to?(:read) &&
|
|
646
|
+
!file_class.method(:read).source_location.nil?
|
|
592
647
|
def file_class.read(*args)
|
|
593
648
|
raise ::Errno::ENOENT, args.first.to_s
|
|
594
649
|
end
|
|
@@ -606,10 +661,14 @@ begin
|
|
|
606
661
|
while i < p.length
|
|
607
662
|
c = p[i]
|
|
608
663
|
case c
|
|
609
|
-
when
|
|
610
|
-
|
|
611
|
-
when
|
|
612
|
-
|
|
664
|
+
when "*"
|
|
665
|
+
regex += ".*"
|
|
666
|
+
when "?"
|
|
667
|
+
regex += "."
|
|
668
|
+
when ".", "(", ")", "[", "]", "+", "^", "$"
|
|
669
|
+
regex += "\\#{c}"
|
|
670
|
+
else
|
|
671
|
+
regex += c
|
|
613
672
|
end
|
|
614
673
|
i += 1
|
|
615
674
|
end
|
|
@@ -628,7 +687,7 @@ end
|
|
|
628
687
|
# Gem::Version at class body eval to gate the `except` override. Opal
|
|
629
688
|
# does not bundle RubyGems — pre-require our minimal stub so the
|
|
630
689
|
# reference resolves before upstream Sinatra loads.
|
|
631
|
-
require
|
|
690
|
+
require "rubygems/version"
|
|
632
691
|
|
|
633
692
|
# Phase 13 originally required `opal-parser` because upstream Sinatra's
|
|
634
693
|
# `set` helper used `class_eval("def ...")` for primitive option values.
|
|
@@ -636,19 +695,47 @@ require 'rubygems/version'
|
|
|
636
695
|
# (Proc-based getters / predicate) so the Workers bundle no longer needs the
|
|
637
696
|
# full Opal compiler + whitequark parser at runtime.
|
|
638
697
|
|
|
639
|
-
[
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
698
|
+
%i[
|
|
699
|
+
ISO_2022_JP
|
|
700
|
+
SHIFT_JIS
|
|
701
|
+
Shift_JIS
|
|
702
|
+
WINDOWS_31J
|
|
703
|
+
CP932
|
|
704
|
+
SJIS
|
|
705
|
+
EUC_JP
|
|
706
|
+
EUC_KR
|
|
707
|
+
EUC_CN
|
|
708
|
+
EUC_TW
|
|
709
|
+
BIG5
|
|
710
|
+
GB18030
|
|
711
|
+
GBK
|
|
712
|
+
GB2312
|
|
713
|
+
WINDOWS_1250
|
|
714
|
+
WINDOWS_1251
|
|
715
|
+
WINDOWS_1252
|
|
716
|
+
WINDOWS_1253
|
|
717
|
+
WINDOWS_1254
|
|
718
|
+
WINDOWS_1255
|
|
719
|
+
WINDOWS_1256
|
|
720
|
+
WINDOWS_1257
|
|
721
|
+
WINDOWS_1258
|
|
722
|
+
KOI8_R
|
|
723
|
+
KOI8_U
|
|
724
|
+
ISO_8859_2
|
|
725
|
+
ISO_8859_3
|
|
726
|
+
ISO_8859_4
|
|
727
|
+
ISO_8859_5
|
|
728
|
+
ISO_8859_6
|
|
729
|
+
ISO_8859_7
|
|
730
|
+
ISO_8859_8
|
|
731
|
+
ISO_8859_9
|
|
732
|
+
ISO_8859_10
|
|
733
|
+
ISO_8859_11
|
|
734
|
+
ISO_8859_13
|
|
735
|
+
ISO_8859_14
|
|
736
|
+
ISO_8859_15
|
|
737
|
+
ISO_8859_16
|
|
738
|
+
MACROMAN
|
|
652
739
|
].each do |name|
|
|
653
740
|
unless Encoding.const_defined?(name)
|
|
654
741
|
Encoding.const_set(name, Encoding::ASCII_8BIT)
|