opal 1.3.1 → 1.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (243) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintrc.js +1 -0
  3. data/.github/workflows/build.yml +20 -21
  4. data/.rubocop.yml +5 -1
  5. data/CHANGELOG.md +119 -11
  6. data/UNRELEASED.md +4 -9
  7. data/benchmark-ips/bm_truthy.rb +30 -0
  8. data/bin/opal-mspec +1 -3
  9. data/bin/opal-repl +1 -2
  10. data/bin/remove-filters +1 -4
  11. data/docs/compiled_ruby.md +37 -22
  12. data/docs/faq.md +1 -1
  13. data/docs/headless_chrome.md +11 -21
  14. data/docs/jquery.md +1 -6
  15. data/docs/opal_parser.md +3 -1
  16. data/docs/promises.md +2 -0
  17. data/docs/releasing.md +3 -0
  18. data/docs/roda-sprockets.md +0 -1
  19. data/docs/source_maps.md +10 -11
  20. data/docs/static_applications.md +2 -2
  21. data/docs/unsupported_features.md +4 -0
  22. data/exe/opal-repl +1 -3
  23. data/lib/opal/ast/builder.rb +1 -1
  24. data/lib/opal/cli.rb +2 -2
  25. data/lib/opal/cli_runners/nodejs.rb +9 -2
  26. data/lib/opal/cli_runners/source-map-support-browser.js +80 -216
  27. data/lib/opal/cli_runners/source-map-support-node.js +80 -216
  28. data/lib/opal/cli_runners/source-map-support.js +5 -1
  29. data/lib/opal/cli_runners/system_runner.rb +10 -4
  30. data/lib/opal/compiler.rb +3 -5
  31. data/lib/opal/fragment.rb +5 -1
  32. data/lib/opal/nodes/args/extract_block_arg.rb +1 -8
  33. data/lib/opal/nodes/args/extract_kwoptarg.rb +1 -3
  34. data/lib/opal/nodes/args/extract_optarg.rb +1 -3
  35. data/lib/opal/nodes/args/extract_post_arg.rb +2 -5
  36. data/lib/opal/nodes/args/extract_post_optarg.rb +2 -7
  37. data/lib/opal/nodes/args/initialize_iterarg.rb +1 -3
  38. data/lib/opal/nodes/args/prepare_post_args.rb +5 -1
  39. data/lib/opal/nodes/base.rb +3 -2
  40. data/lib/opal/nodes/call.rb +20 -9
  41. data/lib/opal/nodes/call_special.rb +50 -0
  42. data/lib/opal/nodes/class.rb +24 -15
  43. data/lib/opal/nodes/constants.rb +23 -5
  44. data/lib/opal/nodes/def.rb +20 -23
  45. data/lib/opal/nodes/defined.rb +5 -5
  46. data/lib/opal/nodes/definitions.rb +2 -2
  47. data/lib/opal/nodes/defs.rb +2 -5
  48. data/lib/opal/nodes/helpers.rb +48 -18
  49. data/lib/opal/nodes/if.rb +113 -8
  50. data/lib/opal/nodes/iter.rb +23 -16
  51. data/lib/opal/nodes/literal.rb +18 -4
  52. data/lib/opal/nodes/logic.rb +2 -1
  53. data/lib/opal/nodes/masgn.rb +4 -9
  54. data/lib/opal/nodes/module.rb +29 -19
  55. data/lib/opal/nodes/node_with_args.rb +1 -7
  56. data/lib/opal/nodes/scope.rb +54 -15
  57. data/lib/opal/nodes/singleton_class.rb +5 -3
  58. data/lib/opal/nodes/super.rb +12 -12
  59. data/lib/opal/nodes/top.rb +34 -31
  60. data/lib/opal/nodes/variables.rb +2 -2
  61. data/lib/opal/nodes/x_string.rb +30 -28
  62. data/lib/opal/nodes.rb +0 -1
  63. data/lib/opal/parser/patch.rb +75 -0
  64. data/lib/opal/parser/with_ruby_lexer.rb +1 -1
  65. data/lib/opal/regexp_anchors.rb +7 -7
  66. data/lib/opal/requires.rb +19 -0
  67. data/lib/opal/rewriters/pattern_matching.rb +1 -1
  68. data/lib/opal/rewriters/returnable_logic.rb +102 -4
  69. data/lib/opal/util.rb +2 -2
  70. data/lib/opal/version.rb +1 -1
  71. data/lib/opal.rb +1 -17
  72. data/opal/corelib/array/pack.rb +11 -11
  73. data/opal/corelib/array.rb +193 -152
  74. data/opal/corelib/basic_object.rb +19 -15
  75. data/opal/corelib/binding.rb +7 -7
  76. data/opal/corelib/boolean.rb +12 -15
  77. data/opal/corelib/class.rb +23 -1
  78. data/opal/corelib/comparable.rb +8 -8
  79. data/opal/corelib/complex/base.rb +2 -2
  80. data/opal/corelib/complex.rb +79 -88
  81. data/opal/corelib/constants.rb +9 -9
  82. data/opal/corelib/dir.rb +4 -3
  83. data/opal/corelib/enumerable.rb +140 -127
  84. data/opal/corelib/enumerator/arithmetic_sequence.rb +177 -0
  85. data/opal/corelib/enumerator/chain.rb +42 -0
  86. data/opal/corelib/enumerator/generator.rb +35 -0
  87. data/opal/corelib/enumerator/lazy.rb +243 -0
  88. data/opal/corelib/enumerator/yielder.rb +36 -0
  89. data/opal/corelib/enumerator.rb +45 -300
  90. data/opal/corelib/error/errno.rb +47 -0
  91. data/opal/corelib/error.rb +62 -60
  92. data/opal/corelib/file.rb +26 -12
  93. data/opal/corelib/hash.rb +98 -107
  94. data/opal/corelib/helpers.rb +62 -13
  95. data/opal/corelib/io.rb +48 -35
  96. data/opal/corelib/kernel/format.rb +29 -29
  97. data/opal/corelib/kernel.rb +86 -83
  98. data/opal/corelib/main.rb +14 -12
  99. data/opal/corelib/marshal/read_buffer.rb +15 -15
  100. data/opal/corelib/marshal/write_buffer.rb +45 -44
  101. data/opal/corelib/marshal.rb +3 -3
  102. data/opal/corelib/math.rb +50 -50
  103. data/opal/corelib/method.rb +12 -8
  104. data/opal/corelib/module.rb +79 -75
  105. data/opal/corelib/nil.rb +9 -11
  106. data/opal/corelib/number.rb +113 -118
  107. data/opal/corelib/numeric.rb +37 -33
  108. data/opal/corelib/object_space.rb +11 -10
  109. data/opal/corelib/pack_unpack/format_string_parser.rb +3 -3
  110. data/opal/corelib/pattern_matching/base.rb +7 -7
  111. data/opal/corelib/pattern_matching.rb +1 -1
  112. data/opal/corelib/proc.rb +15 -16
  113. data/opal/corelib/process/base.rb +2 -2
  114. data/opal/corelib/process/status.rb +21 -0
  115. data/opal/corelib/process.rb +5 -5
  116. data/opal/corelib/random/formatter.rb +11 -11
  117. data/opal/corelib/random/math_random.js.rb +1 -1
  118. data/opal/corelib/random/mersenne_twister.rb +3 -3
  119. data/opal/corelib/random/seedrandom.js.rb +3 -3
  120. data/opal/corelib/random.rb +17 -17
  121. data/opal/corelib/range.rb +51 -35
  122. data/opal/corelib/rational/base.rb +4 -4
  123. data/opal/corelib/rational.rb +61 -62
  124. data/opal/corelib/regexp.rb +54 -45
  125. data/opal/corelib/runtime.js +247 -141
  126. data/opal/corelib/string/encoding.rb +21 -21
  127. data/opal/corelib/string/unpack.rb +19 -14
  128. data/opal/corelib/string.rb +137 -130
  129. data/opal/corelib/struct.rb +59 -46
  130. data/opal/corelib/time.rb +47 -57
  131. data/opal/corelib/trace_point.rb +2 -2
  132. data/opal/corelib/unsupported.rb +31 -120
  133. data/opal/corelib/variables.rb +3 -3
  134. data/opal/opal/base.rb +9 -8
  135. data/opal/opal/full.rb +8 -8
  136. data/opal/opal/mini.rb +17 -17
  137. data/opal/opal.rb +17 -18
  138. data/opal.gemspec +1 -1
  139. data/spec/filters/bugs/array.rb +4 -24
  140. data/spec/filters/bugs/basicobject.rb +0 -1
  141. data/spec/filters/bugs/bigdecimal.rb +0 -23
  142. data/spec/filters/bugs/binding.rb +0 -1
  143. data/spec/filters/bugs/boolean.rb +3 -0
  144. data/spec/filters/bugs/class.rb +2 -0
  145. data/spec/filters/bugs/date.rb +0 -5
  146. data/spec/filters/bugs/encoding.rb +8 -50
  147. data/spec/filters/bugs/enumerable.rb +4 -1
  148. data/spec/filters/bugs/enumerator.rb +3 -36
  149. data/spec/filters/bugs/exception.rb +0 -2
  150. data/spec/filters/bugs/file.rb +0 -2
  151. data/spec/filters/bugs/float.rb +0 -3
  152. data/spec/filters/bugs/hash.rb +5 -3
  153. data/spec/filters/bugs/integer.rb +2 -3
  154. data/spec/filters/bugs/kernel.rb +2 -31
  155. data/spec/filters/bugs/language.rb +29 -49
  156. data/spec/filters/bugs/main.rb +0 -2
  157. data/spec/filters/bugs/marshal.rb +2 -3
  158. data/spec/filters/bugs/matrix.rb +0 -36
  159. data/spec/filters/bugs/module.rb +7 -61
  160. data/spec/filters/bugs/numeric.rb +0 -7
  161. data/spec/filters/bugs/objectspace.rb +1 -1
  162. data/spec/filters/bugs/pack_unpack.rb +0 -4
  163. data/spec/filters/bugs/proc.rb +0 -9
  164. data/spec/filters/bugs/random.rb +0 -5
  165. data/spec/filters/bugs/range.rb +1 -6
  166. data/spec/filters/bugs/regexp.rb +0 -3
  167. data/spec/filters/bugs/set.rb +8 -1
  168. data/spec/filters/bugs/string.rb +9 -34
  169. data/spec/filters/bugs/stringscanner.rb +8 -7
  170. data/spec/filters/bugs/struct.rb +2 -3
  171. data/spec/filters/bugs/symbol.rb +0 -1
  172. data/spec/filters/bugs/time.rb +0 -8
  173. data/spec/filters/bugs/unboundmethod.rb +0 -8
  174. data/spec/filters/bugs/warnings.rb +1 -7
  175. data/spec/filters/unsupported/freeze.rb +24 -0
  176. data/spec/filters/unsupported/integer.rb +1 -0
  177. data/spec/filters/unsupported/kernel.rb +12 -0
  178. data/spec/filters/unsupported/privacy.rb +3 -0
  179. data/spec/filters/unsupported/string.rb +2 -0
  180. data/spec/lib/builder_spec.rb +2 -2
  181. data/spec/lib/cli_spec.rb +1 -1
  182. data/spec/lib/compiler_spec.rb +37 -37
  183. data/spec/lib/simple_server_spec.rb +2 -2
  184. data/spec/lib/source_map/file_spec.rb +1 -1
  185. data/spec/opal/compiler/irb_spec.rb +2 -2
  186. data/spec/opal/core/io/read_spec.rb +69 -0
  187. data/spec/opal/core/kernel/puts_spec.rb +90 -0
  188. data/spec/opal/core/language/super_spec.rb +21 -0
  189. data/spec/opal/core/language/xstring_spec.rb +13 -0
  190. data/spec/opal/core/language_spec.rb +14 -0
  191. data/spec/opal/core/string/gsub_spec.rb +8 -0
  192. data/spec/ruby_specs +4 -2
  193. data/spec/support/rewriters_helper.rb +1 -1
  194. data/stdlib/bigdecimal.rb +7 -11
  195. data/stdlib/buffer/view.rb +2 -2
  196. data/stdlib/buffer.rb +2 -2
  197. data/stdlib/date.rb +5 -6
  198. data/stdlib/erb.rb +1 -0
  199. data/stdlib/js.rb +2 -1
  200. data/stdlib/native.rb +7 -8
  201. data/stdlib/nodejs/argf.rb +4 -4
  202. data/stdlib/nodejs/base.rb +29 -0
  203. data/stdlib/nodejs/dir.rb +1 -1
  204. data/stdlib/nodejs/env.rb +6 -9
  205. data/stdlib/nodejs/file.rb +23 -17
  206. data/stdlib/nodejs/fileutils.rb +3 -3
  207. data/stdlib/nodejs/io.rb +2 -20
  208. data/stdlib/nodejs/irb.rb +0 -0
  209. data/stdlib/nodejs/kernel.rb +2 -37
  210. data/stdlib/nodejs.rb +1 -3
  211. data/stdlib/opal/miniracer.rb +2 -0
  212. data/stdlib/opal/platform.rb +6 -13
  213. data/stdlib/opal/replutils.rb +16 -5
  214. data/stdlib/opal-parser.rb +2 -2
  215. data/stdlib/optparse/ac.rb +54 -0
  216. data/stdlib/optparse/date.rb +14 -0
  217. data/stdlib/optparse/kwargs.rb +22 -0
  218. data/stdlib/optparse/shellwords.rb +7 -0
  219. data/stdlib/optparse/time.rb +15 -0
  220. data/stdlib/optparse/uri.rb +7 -0
  221. data/stdlib/optparse/version.rb +69 -0
  222. data/stdlib/optparse.rb +2279 -0
  223. data/stdlib/pathname.rb +5 -6
  224. data/stdlib/pp.rb +18 -2
  225. data/stdlib/promise/v2.rb +18 -29
  226. data/stdlib/promise.rb +15 -21
  227. data/stdlib/quickjs/io.rb +0 -2
  228. data/stdlib/quickjs/kernel.rb +0 -2
  229. data/stdlib/quickjs.rb +2 -0
  230. data/stdlib/set.rb +32 -32
  231. data/stdlib/shellwords.rb +240 -0
  232. data/stdlib/stringio.rb +3 -6
  233. data/stdlib/strscan.rb +5 -8
  234. data/stdlib/template.rb +2 -2
  235. data/stdlib/thread.rb +7 -9
  236. data/tasks/linting-parse-eslint-results.js +1 -0
  237. data/tasks/linting.rake +0 -10
  238. data/tasks/performance.rake +5 -2
  239. data/tasks/testing/mspec_special_calls.rb +0 -12
  240. data/tasks/testing.rake +55 -37
  241. data/test/nodejs/test_file.rb +11 -0
  242. metadata +55 -8
  243. data/lib/opal/nodes/case.rb +0 -114
data/stdlib/pathname.rb CHANGED
@@ -165,12 +165,6 @@ class Pathname
165
165
  path <=> other.path
166
166
  end
167
167
 
168
- alias eql? ==
169
- alias === ==
170
-
171
- alias to_str to_path
172
- alias to_s to_path
173
-
174
168
  SAME_PATHS = if File::FNM_SYSCASE.nonzero?
175
169
  # Avoid #zero? here because #casecmp can return nil.
176
170
  proc { |a, b| a.casecmp(b) == 0 }
@@ -217,6 +211,11 @@ class Pathname
217
211
  def entries
218
212
  Dir.entries(@path).map { |f| self.class.new(f) }
219
213
  end
214
+
215
+ alias === ==
216
+ alias eql? ==
217
+ alias to_s to_path
218
+ alias to_str to_path
220
219
  end
221
220
 
222
221
  module Kernel
data/stdlib/pp.rb CHANGED
@@ -151,7 +151,23 @@ class PP < PrettyPrint
151
151
  #
152
152
  # Object#pretty_print_cycle is used when +obj+ is already
153
153
  # printed, a.k.a the object reference chain has a cycle.
154
- def pp(obj)
154
+ def pp(obj = undefined)
155
+ # Opal: consider JS-native variables:
156
+ %x{
157
+ if (obj === null) {
158
+ #{text "null"}
159
+ #{return}
160
+ }
161
+ else if (obj === undefined) {
162
+ #{text "undefined"}
163
+ #{return}
164
+ }
165
+ else if (obj.$$class === undefined) {
166
+ #{text `Object.prototype.toString.apply(obj)`}
167
+ #{return}
168
+ }
169
+ }
170
+
155
171
  # If obj is a Delegator then use the object being delegated to for cycle
156
172
  # detection
157
173
  obj = obj.__getobj__ if defined?(::Delegator) and obj.is_a?(::Delegator)
@@ -180,7 +196,7 @@ class PP < PrettyPrint
180
196
  # object_id.
181
197
  def object_address_group(obj, &block)
182
198
  str = Kernel.instance_method(:to_s).bind_call(obj)
183
- str.chomp!('>')
199
+ str = str.chomp('>')
184
200
  group(1, str, '>', &block)
185
201
  end
186
202
 
data/stdlib/promise/v2.rb CHANGED
@@ -98,13 +98,6 @@
98
98
  # end
99
99
  #
100
100
 
101
- if `Opal.config.experimental_features_severity == 'warning'`
102
- warn 'PromiseV2 is a technology preview, which means it may change its behavior ' \
103
- 'in the future until this warning is removed. If you are interested in this part, ' \
104
- 'please make sure you track the async/await/promises tag on Opal issues: ' \
105
- 'https://github.com/opal/opal/issues?q=label%3Aasync%2Fawait%2Fpromises'
106
- end
107
-
108
101
  class PromiseV2 < `Promise`
109
102
  class << self
110
103
  def allocate
@@ -124,8 +117,6 @@ class PromiseV2 < `Promise`
124
117
  end
125
118
  end
126
119
 
127
- alias all when
128
-
129
120
  def all_resolved(*promises)
130
121
  promises = Array(promises.length == 1 ? promises.first : promises)
131
122
  `Promise.allResolved(#{promises})`.tap do |prom|
@@ -154,7 +145,6 @@ class PromiseV2 < `Promise`
154
145
  prom.instance_variable_set(:@value, value)
155
146
  end
156
147
  end
157
- alias value resolve
158
148
 
159
149
  def reject(value = nil)
160
150
  `Promise.reject(#{value})`.tap do |prom|
@@ -163,7 +153,10 @@ class PromiseV2 < `Promise`
163
153
  prom.instance_variable_set(:@value, value)
164
154
  end
165
155
  end
156
+
157
+ alias all when
166
158
  alias error reject
159
+ alias value resolve
167
160
  end
168
161
 
169
162
  attr_reader :prev, :next
@@ -209,7 +202,6 @@ class PromiseV2 < `Promise`
209
202
  @resolve_proc.call(value)
210
203
  self
211
204
  end
212
- alias resolve! resolve
213
205
 
214
206
  def reject(value = nil)
215
207
  nativity_check!
@@ -219,7 +211,6 @@ class PromiseV2 < `Promise`
219
211
  @reject_proc.call(value)
220
212
  self
221
213
  end
222
- alias reject! reject
223
214
 
224
215
  def then(&block)
225
216
  prom = nil
@@ -239,9 +230,6 @@ class PromiseV2 < `Promise`
239
230
  self.then(&block)
240
231
  end
241
232
 
242
- alias do then
243
- alias do! then!
244
-
245
233
  def fail(&block)
246
234
  prom = nil
247
235
  blk = gen_tracing_proc(block) do |val|
@@ -260,11 +248,6 @@ class PromiseV2 < `Promise`
260
248
  fail(&block)
261
249
  end
262
250
 
263
- alias rescue fail
264
- alias catch fail
265
- alias rescue! fail!
266
- alias catch! fail!
267
-
268
251
  def always(&block)
269
252
  prom = nil
270
253
  blk = gen_tracing_proc(block) do |val|
@@ -283,11 +266,6 @@ class PromiseV2 < `Promise`
283
266
  always(&block)
284
267
  end
285
268
 
286
- alias finally always
287
- alias ensure always
288
- alias finally! always!
289
- alias ensure! always!
290
-
291
269
  def trace(depth = nil, &block)
292
270
  prom = self.then do
293
271
  values = []
@@ -362,8 +340,6 @@ class PromiseV2 < `Promise`
362
340
  yield self if block_given?
363
341
  end
364
342
 
365
- alias to_v2 itself
366
-
367
343
  def to_v1
368
344
  v1 = PromiseV1.new
369
345
 
@@ -372,8 +348,6 @@ class PromiseV2 < `Promise`
372
348
  v1
373
349
  end
374
350
 
375
- alias to_n itself
376
-
377
351
  def inspect
378
352
  result = "#<#{self.class}"
379
353
 
@@ -395,4 +369,19 @@ class PromiseV2 < `Promise`
395
369
 
396
370
  result
397
371
  end
372
+
373
+ alias catch fail
374
+ alias catch! fail!
375
+ alias do then
376
+ alias do! then!
377
+ alias ensure always
378
+ alias ensure! always!
379
+ alias finally always
380
+ alias finally! always!
381
+ alias reject! reject
382
+ alias rescue fail
383
+ alias rescue! fail!
384
+ alias resolve! resolve
385
+ alias to_n itself
386
+ alias to_v2 itself
398
387
  end
data/stdlib/promise.rb CHANGED
@@ -275,9 +275,6 @@ class Promise
275
275
  self.then(&block)
276
276
  end
277
277
 
278
- alias do then
279
- alias do! then!
280
-
281
278
  def fail(&block)
282
279
  self ^ Promise.new(failure: block)
283
280
  end
@@ -287,11 +284,6 @@ class Promise
287
284
  fail(&block)
288
285
  end
289
286
 
290
- alias rescue fail
291
- alias catch fail
292
- alias rescue! fail!
293
- alias catch! fail!
294
-
295
287
  def always(&block)
296
288
  self ^ Promise.new(always: block)
297
289
  end
@@ -301,11 +293,6 @@ class Promise
301
293
  always(&block)
302
294
  end
303
295
 
304
- alias finally always
305
- alias ensure always
306
- alias finally! always!
307
- alias ensure! always!
308
-
309
296
  def trace(depth = nil, &block)
310
297
  self ^ Trace.new(depth, block)
311
298
  end
@@ -337,8 +324,6 @@ class Promise
337
324
  result
338
325
  end
339
326
 
340
- alias to_v1 itself
341
-
342
327
  def to_v2
343
328
  v2 = PromiseV2.new
344
329
 
@@ -347,7 +332,18 @@ class Promise
347
332
  v2
348
333
  end
349
334
 
335
+ alias catch fail
336
+ alias catch! fail!
337
+ alias do then
338
+ alias do! then!
339
+ alias ensure always
340
+ alias ensure! always!
341
+ alias finally always
342
+ alias finally! always!
343
+ alias rescue fail
344
+ alias rescue! fail!
350
345
  alias to_n to_v2
346
+ alias to_v1 itself
351
347
 
352
348
  class Trace < self
353
349
  def self.it(promise)
@@ -414,10 +410,6 @@ class Promise
414
410
  end
415
411
  end
416
412
 
417
- alias map collect
418
-
419
- alias reduce inject
420
-
421
413
  def wait(promise)
422
414
  unless Promise === promise
423
415
  promise = Promise.value(promise)
@@ -436,8 +428,6 @@ class Promise
436
428
  self
437
429
  end
438
430
 
439
- alias and wait
440
-
441
431
  def >>(*)
442
432
  super.tap do
443
433
  try
@@ -454,6 +444,10 @@ class Promise
454
444
  end
455
445
  end
456
446
  end
447
+
448
+ alias map collect
449
+ alias reduce inject
450
+ alias and wait
457
451
  end
458
452
  end
459
453
 
data/stdlib/quickjs/io.rb CHANGED
@@ -1,5 +1,3 @@
1
- `/* global std */`
2
-
3
1
  %x{
4
2
  Opal.gvars.stdout.write_proc = function(s) {
5
3
  std.out.printf("%s", s);
@@ -1,5 +1,3 @@
1
- `/* global std, scriptArgs */`
2
-
3
1
  ARGV = `scriptArgs`
4
2
 
5
3
  `Opal.exit = std.exit`
data/stdlib/quickjs.rb CHANGED
@@ -1,2 +1,4 @@
1
+ `/* global std, scriptArgs */`
2
+
1
3
  require 'quickjs/io'
2
4
  require 'quickjs/kernel'
data/stdlib/set.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # Portions Copyright (c) 2002-2013 Akinori MUSHA <knu@iDaemons.org>
2
- class Set
3
- include Enumerable
2
+ class ::Set
3
+ include ::Enumerable
4
4
 
5
5
  def self.[](*ary)
6
6
  new(ary)
@@ -10,7 +10,7 @@ class Set
10
10
  @hash = {}
11
11
 
12
12
  return if enum.nil?
13
- raise ArgumentError, 'value must be enumerable' unless Enumerable === enum
13
+ ::Kernel.raise ::ArgumentError, 'value must be enumerable' unless ::Enumerable === enum
14
14
 
15
15
  if block
16
16
  enum.each { |item| add yield(item) }
@@ -26,12 +26,11 @@ class Set
26
26
 
27
27
  def -(enum)
28
28
  unless enum.respond_to? :each
29
- raise ArgumentError, 'value must be enumerable'
29
+ ::Kernel.raise ::ArgumentError, 'value must be enumerable'
30
30
  end
31
31
 
32
32
  dup.subtract(enum)
33
33
  end
34
- alias difference -
35
34
 
36
35
  def inspect
37
36
  "#<Set: {#{to_a.join(',')}}>"
@@ -42,7 +41,7 @@ class Set
42
41
  true
43
42
  elsif other.instance_of?(self.class)
44
43
  @hash == other.instance_variable_get(:@hash)
45
- elsif other.is_a?(Set) && size == other.size
44
+ elsif other.is_a?(::Set) && size == other.size
46
45
  other.all? { |o| @hash.include?(o) }
47
46
  else
48
47
  false
@@ -53,12 +52,11 @@ class Set
53
52
  @hash[o] = true
54
53
  self
55
54
  end
56
- alias << add
57
55
 
58
56
  def classify(&block)
59
57
  return enum_for(:classify) unless block_given?
60
58
 
61
- result = Hash.new { |h, k| h[k] = self.class.new }
59
+ result = ::Hash.new { |h, k| h[k] = self.class.new }
62
60
 
63
61
  each { |item| result[yield(item)].add item }
64
62
 
@@ -71,7 +69,6 @@ class Set
71
69
  each { |item| result << yield(item) }
72
70
  replace result
73
71
  end
74
- alias map! collect!
75
72
 
76
73
  def delete(o)
77
74
  @hash.delete(o)
@@ -113,8 +110,6 @@ class Set
113
110
  size == before ? nil : self
114
111
  end
115
112
 
116
- alias filter! select!
117
-
118
113
  def add?(o)
119
114
  if include?(o)
120
115
  nil
@@ -145,7 +140,6 @@ class Set
145
140
  def include?(o)
146
141
  @hash.include?(o)
147
142
  end
148
- alias member? include?
149
143
 
150
144
  def merge(enum)
151
145
  enum.each { |item| add item }
@@ -162,7 +156,6 @@ class Set
162
156
  def size
163
157
  @hash.size
164
158
  end
165
- alias length size
166
159
 
167
160
  def subtract(enum)
168
161
  enum.each { |item| delete item }
@@ -171,46 +164,43 @@ class Set
171
164
 
172
165
  def |(enum)
173
166
  unless enum.respond_to? :each
174
- raise ArgumentError, 'value must be enumerable'
167
+ ::Kernel.raise ::ArgumentError, 'value must be enumerable'
175
168
  end
176
169
  dup.merge(enum)
177
170
  end
178
171
 
172
+ %x{
173
+ function is_set(set) {
174
+ #{`set`.is_a?(::Set) || ::Kernel.raise(::ArgumentError, 'value must be a set')}
175
+ }
176
+ }
177
+
179
178
  def superset?(set)
180
- set.is_a?(Set) || raise(ArgumentError, 'value must be a set')
179
+ `is_set(set)`
181
180
  return false if size < set.size
182
181
  set.all? { |o| include?(o) }
183
182
  end
184
183
 
185
- alias >= superset?
186
-
187
184
  def proper_superset?(set)
188
- set.is_a?(Set) || raise(ArgumentError, 'value must be a set')
185
+ `is_set(set)`
189
186
  return false if size <= set.size
190
187
  set.all? { |o| include?(o) }
191
188
  end
192
189
 
193
- alias > proper_superset?
194
-
195
190
  def subset?(set)
196
- set.is_a?(Set) || raise(ArgumentError, 'value must be a set')
191
+ `is_set(set)`
197
192
  return false if set.size < size
198
193
  all? { |o| set.include?(o) }
199
194
  end
200
195
 
201
- alias <= subset?
202
-
203
196
  def proper_subset?(set)
204
- set.is_a?(Set) || raise(ArgumentError, 'value must be a set')
197
+ `is_set(set)`
205
198
  return false if set.size <= size
206
199
  all? { |o| set.include?(o) }
207
200
  end
208
201
 
209
- alias < proper_subset?
210
-
211
202
  def intersect?(set)
212
- raise ArgumentError, 'value must be a set' unless set.is_a?(Set)
213
-
203
+ `is_set(set)`
214
204
  if size < set.size
215
205
  any? { |o| set.include?(o) }
216
206
  else
@@ -222,15 +212,25 @@ class Set
222
212
  !intersect?(set)
223
213
  end
224
214
 
225
- alias + |
226
- alias union |
227
-
228
215
  def to_a
229
216
  @hash.keys
230
217
  end
218
+
219
+ alias + |
220
+ alias < proper_subset?
221
+ alias << add
222
+ alias <= subset?
223
+ alias > proper_superset?
224
+ alias >= superset?
225
+ alias difference -
226
+ alias filter! select!
227
+ alias length size
228
+ alias map! collect!
229
+ alias member? include?
230
+ alias union |
231
231
  end
232
232
 
233
- module Enumerable
233
+ module ::Enumerable
234
234
  def to_set(klass = Set, *args, &block)
235
235
  klass.new(self, *args, &block)
236
236
  end
@@ -0,0 +1,240 @@
1
+ # frozen-string-literal: true
2
+ ##
3
+ # == Manipulates strings like the UNIX Bourne shell
4
+ #
5
+ # This module manipulates strings according to the word parsing rules
6
+ # of the UNIX Bourne shell.
7
+ #
8
+ # The shellwords() function was originally a port of shellwords.pl,
9
+ # but modified to conform to the Shell & Utilities volume of the IEEE
10
+ # Std 1003.1-2008, 2016 Edition [1].
11
+ #
12
+ # === Usage
13
+ #
14
+ # You can use Shellwords to parse a string into a Bourne shell friendly Array.
15
+ #
16
+ # require 'shellwords'
17
+ #
18
+ # argv = Shellwords.split('three blind "mice"')
19
+ # argv #=> ["three", "blind", "mice"]
20
+ #
21
+ # Once you've required Shellwords, you can use the #split alias
22
+ # String#shellsplit.
23
+ #
24
+ # argv = "see how they run".shellsplit
25
+ # argv #=> ["see", "how", "they", "run"]
26
+ #
27
+ # They treat quotes as special characters, so an unmatched quote will
28
+ # cause an ArgumentError.
29
+ #
30
+ # argv = "they all ran after the farmer's wife".shellsplit
31
+ # #=> ArgumentError: Unmatched quote: ...
32
+ #
33
+ # Shellwords also provides methods that do the opposite.
34
+ # Shellwords.escape, or its alias, String#shellescape, escapes
35
+ # shell metacharacters in a string for use in a command line.
36
+ #
37
+ # filename = "special's.txt"
38
+ #
39
+ # system("cat -- #{filename.shellescape}")
40
+ # # runs "cat -- special\\'s.txt"
41
+ #
42
+ # Note the '--'. Without it, cat(1) will treat the following argument
43
+ # as a command line option if it starts with '-'. It is guaranteed
44
+ # that Shellwords.escape converts a string to a form that a Bourne
45
+ # shell will parse back to the original string, but it is the
46
+ # programmer's responsibility to make sure that passing an arbitrary
47
+ # argument to a command does no harm.
48
+ #
49
+ # Shellwords also comes with a core extension for Array, Array#shelljoin.
50
+ #
51
+ # dir = "Funny GIFs"
52
+ # argv = %W[ls -lta -- #{dir}]
53
+ # system(argv.shelljoin + " | less")
54
+ # # runs "ls -lta -- Funny\\ GIFs | less"
55
+ #
56
+ # You can use this method to build a complete command line out of an
57
+ # array of arguments.
58
+ #
59
+ # === Authors
60
+ # * Wakou Aoyama
61
+ # * Akinori MUSHA <knu@iDaemons.org>
62
+ #
63
+ # === Contact
64
+ # * Akinori MUSHA <knu@iDaemons.org> (current maintainer)
65
+ #
66
+ # === Resources
67
+ #
68
+ # 1: {IEEE Std 1003.1-2008, 2016 Edition, the Shell & Utilities volume}[http://pubs.opengroup.org/onlinepubs/9699919799/utilities/contents.html]
69
+
70
+ module Shellwords
71
+ # Splits a string into an array of tokens in the same way the UNIX
72
+ # Bourne shell does.
73
+ #
74
+ # argv = Shellwords.split('here are "two words"')
75
+ # argv #=> ["here", "are", "two words"]
76
+ #
77
+ # Note, however, that this is not a command line parser. Shell
78
+ # metacharacters except for the single and double quotes and
79
+ # backslash are not treated as such.
80
+ #
81
+ # argv = Shellwords.split('ruby my_prog.rb | less')
82
+ # argv #=> ["ruby", "my_prog.rb", "|", "less"]
83
+ #
84
+ # String#shellsplit is a shortcut for this function.
85
+ #
86
+ # argv = 'here are "two words"'.shellsplit
87
+ # argv #=> ["here", "are", "two words"]
88
+ def shellsplit(line)
89
+ line += ' ' # Somehow this is needed for the JS regexp engine
90
+ words = []
91
+ field = String.new
92
+ line.scan(/\s*(?:([^\s\\\'\"]+)|'([^\']*)'|"((?:[^\"\\]|\\.)*)"|(\\.?)|(\S))(\r?\n?\Z|\s)?/m) do |(word, sq, dq, esc, garbage, sep)|
93
+ raise ArgumentError, "Unmatched quote: #{line.inspect}" if garbage
94
+ # 2.2.3 Double-Quotes:
95
+ #
96
+ # The <backslash> shall retain its special meaning as an
97
+ # escape character only when followed by one of the following
98
+ # characters when considered special:
99
+ #
100
+ # $ ` " \ <newline>
101
+ field += (word || sq || (dq && dq.gsub(/\\([$`"\\\n])/, '\\1')) || esc.gsub(/\\(.)/, '\\1'))
102
+ if sep
103
+ words << field
104
+ field = String.new
105
+ end
106
+ end
107
+ words
108
+ end
109
+
110
+ alias shellwords shellsplit
111
+
112
+ module_function :shellsplit, :shellwords
113
+
114
+ class << self
115
+ alias split shellsplit
116
+ end
117
+
118
+ # Escapes a string so that it can be safely used in a Bourne shell
119
+ # command line. +str+ can be a non-string object that responds to
120
+ # +to_s+.
121
+ #
122
+ # Note that a resulted string should be used unquoted and is not
123
+ # intended for use in double quotes nor in single quotes.
124
+ #
125
+ # argv = Shellwords.escape("It's better to give than to receive")
126
+ # argv #=> "It\\'s\\ better\\ to\\ give\\ than\\ to\\ receive"
127
+ #
128
+ # String#shellescape is a shorthand for this function.
129
+ #
130
+ # argv = "It's better to give than to receive".shellescape
131
+ # argv #=> "It\\'s\\ better\\ to\\ give\\ than\\ to\\ receive"
132
+ #
133
+ # # Search files in lib for method definitions
134
+ # pattern = "^[ \t]*def "
135
+ # open("| grep -Ern -e #{pattern.shellescape} lib") { |grep|
136
+ # grep.each_line { |line|
137
+ # file, lineno, matched_line = line.split(':', 3)
138
+ # # ...
139
+ # }
140
+ # }
141
+ #
142
+ # It is the caller's responsibility to encode the string in the right
143
+ # encoding for the shell environment where this string is used.
144
+ #
145
+ # Multibyte characters are treated as multibyte characters, not as bytes.
146
+ #
147
+ # Returns an empty quoted String if +str+ has a length of zero.
148
+ def shellescape(str)
149
+ str = str.to_s
150
+
151
+ # An empty argument will be skipped, so return empty quotes.
152
+ return "''".dup if str.empty?
153
+
154
+ str = str.dup
155
+
156
+ # Treat multibyte characters as is. It is the caller's responsibility
157
+ # to encode the string in the right encoding for the shell
158
+ # environment.
159
+ str = str.gsub(/[^A-Za-z0-9_\-.,:+\/@\n]/, '\\\\\\&')
160
+
161
+ # A LF cannot be escaped with a backslash because a backslash + LF
162
+ # combo is regarded as a line continuation and simply ignored.
163
+ str = str.gsub(/\n/, "'\n'")
164
+
165
+ str
166
+ end
167
+
168
+ module_function :shellescape
169
+
170
+ class << self
171
+ alias escape shellescape
172
+ end
173
+
174
+ # Builds a command line string from an argument list, +array+.
175
+ #
176
+ # All elements are joined into a single string with fields separated by a
177
+ # space, where each element is escaped for the Bourne shell and stringified
178
+ # using +to_s+.
179
+ #
180
+ # ary = ["There's", "a", "time", "and", "place", "for", "everything"]
181
+ # argv = Shellwords.join(ary)
182
+ # argv #=> "There\\'s a time and place for everything"
183
+ #
184
+ # Array#shelljoin is a shortcut for this function.
185
+ #
186
+ # ary = ["Don't", "rock", "the", "boat"]
187
+ # argv = ary.shelljoin
188
+ # argv #=> "Don\\'t rock the boat"
189
+ #
190
+ # You can also mix non-string objects in the elements as allowed in Array#join.
191
+ #
192
+ # output = `#{['ps', '-p', $$].shelljoin}`
193
+ #
194
+ def shelljoin(array)
195
+ array.map { |arg| shellescape(arg) }.join(' ')
196
+ end
197
+
198
+ module_function :shelljoin
199
+
200
+ class << self
201
+ alias join shelljoin
202
+ end
203
+ end
204
+
205
+ class String
206
+ # call-seq:
207
+ # str.shellsplit => array
208
+ #
209
+ # Splits +str+ into an array of tokens in the same way the UNIX
210
+ # Bourne shell does.
211
+ #
212
+ # See Shellwords.shellsplit for details.
213
+ def shellsplit
214
+ Shellwords.split(self)
215
+ end
216
+
217
+ # call-seq:
218
+ # str.shellescape => string
219
+ #
220
+ # Escapes +str+ so that it can be safely used in a Bourne shell
221
+ # command line.
222
+ #
223
+ # See Shellwords.shellescape for details.
224
+ def shellescape
225
+ Shellwords.escape(self)
226
+ end
227
+ end
228
+
229
+ class Array
230
+ # call-seq:
231
+ # array.shelljoin => string
232
+ #
233
+ # Builds a command line string from an argument list +array+ joining
234
+ # all elements escaped for the Bourne shell and separated by a space.
235
+ #
236
+ # See Shellwords.shelljoin for details.
237
+ def shelljoin
238
+ Shellwords.join(self)
239
+ end
240
+ end